Skip to content
Browse files

Add record to binary conversion and ICMP types

Add the corresponding record to binary conversions. These will be used
by procket for packet creation.

Add the ICMP types.

Fix the pseudoheader checksumming. Untested.
  • Loading branch information...
1 parent a944075 commit 7bd31ac8ce2333f4f3b62cb5d002d0b396384cb9 @msantos committed Jun 26, 2010
Showing with 242 additions and 41 deletions.
  1. +21 −11 include/epcap_net.hrl
  2. +221 −30 src/epcap_net.erl
View
32 include/epcap_net.hrl
@@ -8,11 +8,24 @@
-define(IPPROTO_UDP, 17).
-define(ICMP_ECHOREPLY, 0).
+
-define(ICMP_DEST_UNREACH, 3).
+-define( ICMP_UNREACH_NET, 0). % bad net
+-define( ICMP_UNREACH_HOST, 1). % bad host
+-define( ICMP_UNREACH_PROTOCOL, 2). % bad protocol
+-define( ICMP_UNREACH_PORT, 3). % bad port
+-define( ICMP_UNREACH_NEEDFRAG, 4). % IP_DF caused drop
+-define( ICMP_UNREACH_SRCFAIL, 5 ). % src route failed
-define(ICMP_SOURCE_QUENCH, 4).
-define(ICMP_REDIRECT, 5).
+-define( ICMP_REDIRECT_NET, 0). % for network
+-define( ICMP_REDIRECT_HOST, 1). % for host
+-define( ICMP_REDIRECT_TOSNET, 2). % for tos and net
+-define( ICMP_REDIRECT_TOSHOST, 3). % for tos and host
-define(ICMP_ECHO, 8).
-define(ICMP_TIME_EXCEEDED, 11).
+-define( ICMP_TIMXCEED_INTRANS, 0). % ttl==0 in transit
+-define( ICMP_TIMXCEED_REASS, 1). % ttl==0 in reass
-define(ICMP_PARAMETERPROB, 12).
-define(ICMP_TIMESTAMP, 13).
-define(ICMP_TIMESTAMPREPLY, 14).
@@ -29,43 +42,40 @@
}).
-record(ipv4, {
- valid = false,
v = 4, hl = 5, tos = 0, len = 20,
id = 0, df = 0, mf = 0,
off = 0, ttl = 0, p = ?IPPROTO_TCP, sum = 0,
saddr = {127,0,0,1}, daddr = {127,0,0,1}
}).
-record(ipv6, {
- valid = false,
v = 6, class = 0, flow = 0,
len = 40, next = 0, hop = 0,
saddr, daddr
}).
-record(tcp, {
- valid = false,
sport = 0, dport = 0,
seqno = 0,
ackno = 0,
off = 0, cwr = 0, ece = 0, urg = 0, ack = 0,
- psh = 0, rst = 0, syn = 0, fin = 0, win = 0,
+ psh = 0, rst = 0, syn = 0, fin = 0, win = 0,
sum = 0, urp = 0,
opt = <<>>
}).
-record(udp, {
- valid = false,
sport = 0, dport = 0, ulen = 0, sum = 0
}).
-record(icmp, {
- valid,
- type, code, checksum,
- id, sequence,
- gateway,
- un,
- mtu
+ type, code, checksum = 0,
+ id = 0, sequence = 0,
+ gateway = {127,0,0,1},
+ un = <<>>,
+ mtu = 0,
+ pointer = 0,
+ ts_orig = 0, ts_recv = 0, ts_tx = 0
}).
View
251 src/epcap_net.erl
@@ -98,34 +98,59 @@ proto(?IPPROTO_TCP) -> tcp;
proto(?IPPROTO_UDP) -> udp;
proto(_) -> unsupported.
+
+%%
+%% Ethernet
+%%
ether(<<Dhost:6/bytes, Shost:6/bytes, Type:16, Payload/binary>>) ->
% Len = byte_size(Packet) - 4,
% <<Payload:Len/bytes, CRC:4/bytes>> = Packet,
{#ether{
dhost = Dhost, shost = Shost,
type = Type
- }, Payload}.
+ }, Payload};
+ether(#ether{
+ dhost = Dhost, shost = Shost,
+ type = Type
+ }) ->
+ <<Dhost:6/bytes, Shost:6/bytes, Type:16>>.
+
+%%
+%% IPv4
+%%
ipv4(
<<4:4, HL:4, ToS:8, Len:16,
Id:16, 0:1, DF:1, MF:1, %% RFC791 states it's a MUST
Off:13, TTL:8, P:8, Sum:16,
SA1:8, SA2:8, SA3:8, SA4:8,
DA1:8, DA2:8, DA3:8, DA4:8,
- Payload/binary>> = Raw
+ Payload/binary>>
) ->
- <<Hdr:160/bitstring, _/binary>> = Raw,
- Valid = makesum(Hdr) =:= 0,
-
{#ipv4{
- valid = Valid,
hl = HL, tos = ToS, len = Len,
id = Id, df = DF, mf = MF,
off = Off, ttl = TTL, p = P, sum = Sum,
saddr = {SA1,SA2,SA3,SA4},
daddr = {DA1,DA2,DA3,DA4}
- }, Payload}.
+ }, Payload};
+ipv4(#ipv4{
+ hl = HL, tos = ToS, len = Len,
+ id = Id, df = DF, mf = MF,
+ off = Off, ttl = TTL, p = P, sum = Sum,
+ saddr = {SA1,SA2,SA3,SA4},
+ daddr = {DA1,DA2,DA3,DA4}
+ }) ->
+ <<4:4, HL:4, ToS:8, Len:16,
+ Id:16, 0:1, DF:1, MF:1, %% RFC791 states it's a MUST
+ Off:13, TTL:8, P:8, Sum:16,
+ SA1:8, SA2:8, SA3:8, SA4:8,
+ DA1:8, DA2:8, DA3:8, DA4:8>>.
+
+%%
+%% IPv6
+%%
ipv6(
<<6:4, Class:8, Flow:20,
Len:16, Next:8, Hop:8,
@@ -134,12 +159,24 @@ ipv6(
Payload/binary>>
) ->
{#ipv6{
- valid = false,
class = Class, flow = Flow,
len = Len, next = Next, hop = Hop,
saddr = Src, daddr = Dst
- }, Payload}.
+ }, Payload};
+ipv6(#ipv6{
+ class = Class, flow = Flow,
+ len = Len, next = Next, hop = Hop,
+ saddr = Src, daddr = Dst
+ }) ->
+ <<6:4, Class:8, Flow:20,
+ Len:16, Next:8, Hop:8,
+ Src:128,
+ Dst:128>>.
+
+%%
+%% TCP
+%%
tcp(
<<SPort:16, DPort:16,
SeqNo:32,
@@ -149,7 +186,7 @@ tcp(
Sum:16, Urp:16,
Payload/binary>>
) ->
- {Opt, Msg} = tcp_options(tcp_offset(Off), Payload),
+ {Opt, Data} = tcp_options(tcp_offset(Off), Payload),
{#tcp{
sport = SPort, dport = DPort,
seqno = SeqNo,
@@ -158,7 +195,21 @@ tcp(
psh = PSH, rst = RST, syn = SYN, fin = FIN, win = Win,
sum = Sum, urp = Urp,
opt = Opt
- }, Msg}.
+ }, Data};
+tcp(#tcp{
+ sport = SPort, dport = DPort,
+ seqno = SeqNo,
+ ackno = AckNo,
+ off = Off, cwr = CWR, ece = ECE, urg = URG, ack = ACK,
+ psh = PSH, rst = RST, syn = SYN, fin = FIN, win = Win,
+ sum = Sum, urp = Urp
+ }) ->
+ <<SPort:16, DPort:16,
+ SeqNo:32,
+ AckNo:32,
+ Off:4, 0:4, CWR:1, ECE:1, URG:1, ACK:1,
+ PSH:1, RST:1, SYN:1, FIN:1, Win:16,
+ Sum:16, Urp:16>>.
tcp_offset(N) when N > 5 -> (N - 5) * 4;
tcp_offset(_) -> 0.
@@ -169,47 +220,187 @@ tcp_options(Offset, Payload) when Offset > 0 ->
tcp_options(_, Payload) ->
{<<>>, Payload}.
+
+%%
+%% UDP
+%%
udp(<<SPort:16, DPort:16, ULen:16, Sum:16, Payload/binary>>) ->
- {#udp{sport = SPort, dport = DPort, ulen = ULen, sum = Sum}, Payload}.
+ {#udp{sport = SPort, dport = DPort, ulen = ULen, sum = Sum}, Payload};
+udp(#udp{sport = SPort, dport = DPort, ulen = ULen, sum = Sum}) ->
+ <<SPort:16, DPort:16, ULen:16, Sum:16>>.
-icmp(<<?ICMP_ECHO:8, Code:8, Checksum:16, Id:16, Sequence:16, Payload/binary>>) ->
+
+%%
+%% ICMP
+%%
+
+% Destination Unreachable Message
+icmp(<<?ICMP_DEST_UNREACH:8, Code:8, Checksum:16, _Unused:32, Payload/binary>>) ->
{#icmp{
- type = ?ICMP_ECHO, code = Code, checksum = Checksum, id = Id,
- sequence = Sequence
+ type = ?ICMP_DEST_UNREACH, code = Code, checksum = Checksum
+ }, Payload};
+icmp(#icmp{
+ type = ?ICMP_DEST_UNREACH, code = Code, checksum = Checksum
+ }) ->
+ <<?ICMP_DEST_UNREACH:8, Code:8, Checksum:16>>;
+
+% Time Exceeded Message
+icmp(<<?ICMP_TIME_EXCEEDED:8, Code:8, Checksum:16, _Unused:32, Payload/binary>>) ->
+ {#icmp{
+ type = ?ICMP_TIME_EXCEEDED, code = Code, checksum = Checksum
+ }, Payload};
+icmp(#icmp{
+ type = ?ICMP_TIME_EXCEEDED, code = Code, checksum = Checksum
+ }) ->
+ <<?ICMP_TIME_EXCEEDED:8, Code:8, Checksum:16>>;
+
+% Parameter Problem Message
+icmp(<<?ICMP_PARAMETERPROB:8, Code:8, Checksum:16, Pointer:8, _Unused:24, Payload/binary>>) ->
+ {#icmp{
+ type = ?ICMP_PARAMETERPROB, code = Code, checksum = Checksum, pointer = Pointer
+ }, Payload};
+icmp(#icmp{
+ type = ?ICMP_PARAMETERPROB, code = Code, checksum = Checksum, pointer = Pointer
+ }) ->
+ <<?ICMP_PARAMETERPROB:8, Code:8, Checksum:16, Pointer:8>>;
+
+% Source Quench Message
+icmp(<<?ICMP_SOURCE_QUENCH:8, 0:8, Checksum:16, _Unused:32, Payload/binary>>) ->
+ {#icmp{
+ type = ?ICMP_SOURCE_QUENCH, code = 0, checksum = Checksum
}, Payload};
+icmp(#icmp{
+ type = ?ICMP_SOURCE_QUENCH, code = Code, checksum = Checksum
+ }) ->
+ <<?ICMP_SOURCE_QUENCH:8, Code:8, Checksum:16>>;
-% PLACEHOLDER: gateway
-icmp(<<?ICMP_DEST_UNREACH:8, Code:8, Checksum:16, Gateway:32, Payload/binary>>) ->
+% Redirect Message
+icmp(<<?ICMP_REDIRECT:8, Code:8, Checksum:16, DA1, DA2, DA3, DA4, Payload/binary>>) ->
{#icmp{
- type = ?ICMP_DEST_UNREACH, code = Code, checksum = Checksum, gateway = Gateway
+ type = ?ICMP_REDIRECT, code = Code, checksum = Checksum, gateway = {DA1,DA2,DA3,DA4}
}, Payload};
+icmp(#icmp{
+ type = ?ICMP_REDIRECT, code = Code, checksum = Checksum, gateway = {DA1,DA2,DA3,DA4}
+ }) ->
+ <<?ICMP_REDIRECT:8, Code:8, Checksum:16, DA1, DA2, DA3, DA4>>;
-% PLACEHOLDER: frag
-icmp(<<?ICMP_DEST_UNREACH:8, Code:8, Checksum:16, _Unused:16, MTU:16, Payload/binary>>) ->
+% Echo or Echo Reply Message
+icmp(<<?ICMP_ECHO:8, Code:8, Checksum:16, Id:16, Sequence:16, Payload/binary>>) ->
{#icmp{
- type = ?ICMP_DEST_UNREACH, code = Code, checksum = Checksum, mtu = MTU
+ type = ?ICMP_ECHO, code = Code, checksum = Checksum, id = Id,
+ sequence = Sequence
}, Payload};
+icmp(#icmp{
+ type = ?ICMP_ECHO, code = Code, checksum = Checksum, id = Id,
+ sequence = Sequence
+ }) ->
+ <<?ICMP_ECHO:8, Code:8, Checksum:16, Id:16, Sequence:16>>;
+
+% Timestamp or Timestamp Reply Message
+icmp(<<Type:8, 0:8, Checksum:16, Id:16, Sequence:16, TS_Orig:32, TS_Recv:32, TS_Tx:32>>)
+when Type =:= ?ICMP_TIMESTAMP; Type =:= ?ICMP_TIMESTAMPREPLY ->
+ {#icmp{
+ type = Type, code = 0, checksum = Checksum, id = Id,
+ sequence = Sequence, ts_orig = TS_Orig, ts_recv = TS_Recv, ts_tx = TS_Tx
+ }, <<>>};
+icmp(#icmp{
+ type = Type, code = Code, checksum = Checksum, id = Id,
+ sequence = Sequence, ts_orig = TS_Orig, ts_recv = TS_Recv, ts_tx = TS_Tx
+ }) when Type =:= ?ICMP_TIMESTAMP; Type =:= ?ICMP_TIMESTAMPREPLY ->
+ <<Type:8, Code:8, Checksum:16, Id:16, Sequence:16, TS_Orig:32, TS_Recv:32, TS_Tx:32>>;
+
+% Information Request or Information Reply Message
+icmp(<<Type:8, 0:8, Checksum:16, Id:16, Sequence:16>>)
+when Type =:= ?ICMP_INFO_REQUEST; Type =:= ?ICMP_INFO_REPLY ->
+ {#icmp{
+ type = Type, code = 0, checksum = Checksum, id = Id,
+ sequence = Sequence
+ }, <<>>};
+icmp(#icmp{
+ type = Type, code = Code, checksum = Checksum, id = Id,
+ sequence = Sequence
+ }) when Type =:= ?ICMP_INFO_REQUEST; Type =:= ?ICMP_INFO_REPLY ->
+ <<Type:8, Code:8, Checksum:16, Id:16, Sequence:16>>;
-% Catch unknown types
+% Catch/build arbitrary types
icmp(<<Type:8, Code:8, Checksum:16, Un:32, Payload/binary>>) ->
{#icmp{
type = Type, code = Code, checksum = Checksum, un = Un
- }, Payload}.
+ }, Payload};
+icmp(#icmp{type = Type, code = Code, checksum = Checksum, un = Un}) ->
+ <<Type:8, Code:8, Checksum:16, Un:32>>.
+
+%%
+%% Utility functions
+%%
payload(Payload) ->
[ to_ascii(C) || <<C:8>> <= Payload ].
checksum(Hdr) ->
lists:foldl(fun compl/2, 0, [ W || <<W:16>> <= Hdr ]).
-checksum(tcp, #ipv4{saddr = {S1,S2,S3,S4}, daddr = {D1,D2,D3,D4}, p = P},
- <<Head:16/bytes, _:2/bytes, Trailer/binary>> = Payload) ->
- Len = byte_size(Payload),
- PseudoHdr = case Len rem 2 of
- 0 -> <<S1,S2,S3,S4,D1,D2,D3,D4,0:8,P,Len:16,Head/bytes,0:16,Trailer/bytes>>;
- 1 -> <<S1,S2,S3,S4,D1,D2,D3,D4,0:8,P,Len:16,Head/bytes,0:16,Trailer/bytes,0>>
+% TCP pseudoheader checksum
+checksum(#ipv4{
+ saddr = {SA1,SA2,SA3,SA4},
+ daddr = {DA1,DA2,DA3,DA4},
+ p = Protocol
+ },
+ #tcp{
+ off = Off
+ } = TCPhdr,
+ Payload
+) ->
+ Len = Off * 4,
+ TCP = tcp(TCPhdr#tcp{sum = 0}),
+ Pad = case Len rem 2 of
+ 0 -> 0;
+ 1 -> 8
+ end,
+ checksum(
+ list_to_binary([
+ <<SA1,SA2,SA3,SA4,
+ DA1,DA2,DA3,DA4,
+ 0:8,
+ Protocol:8,
+ Len:16>>,
+ TCP,
+ Payload,
+ <<0:Pad>>
+ ]));
+
+% UDP pseudoheader checksum
+checksum(#ipv4{
+ saddr = {SA1,SA2,SA3,SA4},
+ daddr = {DA1,DA2,DA3,DA4},
+ p = Protocol
+ },
+ #udp{
+ sport = SPort,
+ dport = DPort,
+ ulen = Len
+ },
+ Payload
+) ->
+ Pad = case Len rem 2 of
+ 0 -> 0;
+ 1 -> 8
end,
- checksum(PseudoHdr).
+ checksum(
+ list_to_binary([
+ <<SA1,SA2,SA3,SA4,
+ DA1,DA2,DA3,DA4,
+ 0:8,
+ Protocol:8,
+ Len:16,
+
+ SPort:16,
+ DPort:16,
+ Len:16,
+ 0:16,
+ Payload/binary,
+ 0:Pad>>
+ ])).
makesum(Hdr) -> 16#FFFF - checksum(Hdr).

0 comments on commit 7bd31ac

Please sign in to comment.
Something went wrong with that request. Please try again.