Skip to content

Commit 06286c3

Browse files
author
Marco Canini
committed
Merge pull request #29 from frenetic-lang/checksum
Compute TCP checksum
2 parents d92c0b5 + 8eeb50d commit 06286c3

File tree

2 files changed

+43
-16
lines changed

2 files changed

+43
-16
lines changed

lib/Packet.ml

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,18 @@ type nwTos = int8
8686

8787
type tpPort = int16
8888

89+
let mk_pseudo_header (src : nwAddr) (dst : nwAddr) (proto : int) (len : int) =
90+
(* XXX(seliopou): pseudo_header's allocated on every call. Given the usage
91+
* pattern of this library, though, would it be safe to allocate once and
92+
* reuse? *)
93+
let pseudo_header = Cstruct.create 12 in
94+
Cstruct.BE.set_uint32 pseudo_header 0 src;
95+
Cstruct.BE.set_uint32 pseudo_header 4 dst;
96+
Cstruct.set_uint8 pseudo_header 8 0;
97+
Cstruct.set_uint8 pseudo_header 9 proto;
98+
Cstruct.BE.set_uint16 pseudo_header 10 len;
99+
pseudo_header
100+
89101
module Tcp = struct
90102

91103
module Flags = struct
@@ -202,6 +214,16 @@ module Tcp = struct
202214
let bits = Cstruct.shift bits sizeof_tcp in
203215
Cstruct.blit pkt.payload 0 bits 0 (Cstruct.len pkt.payload)
204216

217+
218+
let checksum (bits : Cstruct.t) (src : nwAddr) (dst : nwAddr) (pkt : t) =
219+
let length = len pkt in
220+
let pseudo_header = mk_pseudo_header src dst 0x6 length in
221+
set_tcp_chksum bits 0;
222+
let chksum = Checksum.ones_complement_list
223+
(if (length mod 2) = 0
224+
then [pseudo_header; Cstruct.sub bits 0 length]
225+
else [pseudo_header; Cstruct.sub bits 0 length; Cstruct.of_string "\x00"]) in
226+
set_tcp_chksum bits chksum
205227
end
206228

207229
module Udp = struct
@@ -883,7 +905,8 @@ module Ip = struct
883905
let bits = Cstruct.shift bits header_len in
884906
match pkt.tp with
885907
| Tcp tcp ->
886-
Tcp.marshal bits tcp
908+
Tcp.marshal bits tcp;
909+
Tcp.checksum bits pkt.src pkt.dst tcp
887910
| Udp udp ->
888911
Udp.marshal bits udp
889912
| Icmp icmp ->
@@ -1118,15 +1141,15 @@ let setNwTos pkt nwTos =
11181141

11191142
let tp_setTpSrc tp src = match tp with
11201143
| Ip.Tcp tcp ->
1121-
Ip.Tcp { tcp with Tcp.src = src } (* JNF: checksum? *)
1144+
Ip.Tcp { tcp with Tcp.src = src }
11221145
| Ip.Udp udp ->
11231146
Ip.Udp { udp with Udp.src = src }
11241147
| tp ->
11251148
tp
11261149

11271150
let tp_setTpDst tp dst = match tp with
11281151
| Ip.Tcp tcp ->
1129-
Ip.Tcp { tcp with Tcp.dst = dst } (* JNF: checksum? *)
1152+
Ip.Tcp { tcp with Tcp.dst = dst }
11301153
| Ip.Udp udp ->
11311154
Ip.Udp { udp with Udp.dst = dst }
11321155
| tp ->

test/Test.ml

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ module RoundTrip = struct
1717
let unparsable_eq (l1, b1) (l2, b2) =
1818
l1 = l2 && compare (Cstruct.to_string b1) (Cstruct.to_string b2) = 0
1919

20-
let udp_eq e1 e2 =
20+
let udp_eq ?(chksum=false) e1 e2 =
2121
let open Udp in
2222
e1.src = e2.src &&
2323
e1.dst = e2.dst &&
24-
e1.chksum = e2.chksum &&
24+
((not chksum) || e1.chksum = e2.chksum) &&
2525
compare (Cstruct.to_string e1.payload) (Cstruct.to_string e2.payload) = 0
2626

27-
let tcp_eq e1 e2 =
27+
let tcp_eq ?(chksum=false) e1 e2 =
2828
let open Tcp in
2929
e1.src = e2.src &&
3030
e1.dst = e2.dst &&
@@ -33,11 +33,11 @@ module RoundTrip = struct
3333
e1.offset = e2.offset &&
3434
e1.flags = e2.flags &&
3535
e1.window = e2.window &&
36-
e1.chksum = e2.chksum &&
3736
e1.urgent = e2.urgent &&
37+
((not chksum) || e1.chksum = e2.chksum) &&
3838
compare (Cstruct.to_string e1.payload) (Cstruct.to_string e2.payload) = 0
3939

40-
let ip_eq e1 e2 =
40+
let ip_eq ?(chksum=false) e1 e2 =
4141
let open Ip in
4242
e1.tos = e2.tos &&
4343
e1.ident = e2.ident &&
@@ -50,13 +50,13 @@ module RoundTrip = struct
5050
| Unparsable u1, Unparsable u2 ->
5151
unparsable_eq u1 u2
5252
| Udp p1, Udp p2 ->
53-
udp_eq p1 p2
53+
udp_eq ~chksum p1 p2
5454
| Tcp p1, Tcp p2 ->
55-
tcp_eq p1 p2
55+
tcp_eq ~chksum p1 p2
5656
| _, _ ->
5757
e1 = e2
5858

59-
let dl_eq e1 e2 =
59+
let dl_eq ?(chksum=false) e1 e2 =
6060
e1.dlSrc = e2.dlSrc &&
6161
e1.dlDst = e2.dlDst &&
6262
e1.dlVlan = e2.dlVlan &&
@@ -65,12 +65,16 @@ module RoundTrip = struct
6565
| Unparsable u1, Unparsable u2 ->
6666
unparsable_eq u1 u2
6767
| Ip nw1, Ip nw2 ->
68-
ip_eq nw1 nw2
68+
ip_eq ~chksum nw1 nw2
6969
| _, _ ->
7070
e1 = e2
7171

72-
let prop_roundtrip parse marshal e =
73-
dl_eq (parse (marshal e)) e
72+
let prop_roundtrip ?(chksum=false) parse marshal e =
73+
dl_eq ~chksum (parse (marshal e)) e
74+
75+
let prop_roundtrip2 parse marshal e =
76+
let e' = parse (marshal e) in
77+
prop_roundtrip ~chksum:true parse marshal e'
7478

7579
TEST "Roundtrip property for unparsable Ethernet frames" =
7680
(packet_quickCheck (Arb.arbitrary_packet Arb.arbitrary_dl_unparsable)
@@ -92,13 +96,13 @@ module RoundTrip = struct
9296
let udp = Gen.map_gen (fun x -> Ip.Udp(x))
9397
(Arb.arbitrary_udp (Arb.arbitrary_payload 65507)) in
9498
(packet_quickCheck (mk_ip udp)
95-
(prop_roundtrip parse marshal))
99+
(prop_roundtrip2 parse marshal))
96100

97101
TEST "Roundtrip property for TCP packets" =
98102
let tcp = Gen.map_gen (fun x -> Ip.Tcp(x))
99103
(Arb.arbitrary_tcp (Arb.arbitrary_payload (65507 - 128))) in
100104
(packet_quickCheck (mk_ip tcp)
101-
(prop_roundtrip parse marshal))
105+
(prop_roundtrip2 parse marshal))
102106

103107
end
104108

0 commit comments

Comments
 (0)