]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ipfilter/test/vfycksum.pl
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ipfilter / test / vfycksum.pl
1
2 #
3 # validate the IPv4 header checksum.
4 # $bytes[] is an array of 16bit values, with $cnt elements in the array.
5 #
6 sub dump {
7         print "\n";
8         for ($i = 0; $i < $#bytes; $i++) {
9                 printf "%04x ", $bytes[$i];
10         }
11         print "\n";
12 }
13
14 sub dosum {
15         local($seed) = $_[0];
16         local($start) = $_[1];
17         local($max) = $_[2];
18         local($idx) = $start;
19         local($lsum) = $seed;
20
21         for ($idx = $start, $lsum = $seed; $idx < $max; $idx++) {
22                 $lsum += $bytes[$idx];
23         }
24         $lsum = ($lsum & 0xffff) + ($lsum >> 16);
25         $lsum = ~$lsum & 0xffff;
26         return $lsum;
27 }
28
29 sub ipv4check {
30         local($base) = $_[0];
31         $hl = $bytes[$base] / 256;
32         return if (($hl >> 4) != 4);    # IPv4 ?
33         $hl &= 0xf;
34         $hl <<= 1;                      # get the header length in 16bit words
35
36         $hs = &dosum(0, $base, $base + $hl);
37         $osum = $bytes[$base + 5];
38
39         if ($hs != 0) {
40                 $bytes[$base + 5] = 0;
41                 $hs2 = &dosum(0, $base, $base + $hl);
42                 $bytes[$base + 5] = $osum;
43                 printf " IP: ($hl,%x) %x != %x", $hs, $osum, $hs2;
44         } else {
45                 print " IP($base): ok ";
46         }
47
48         #
49         # Recognise TCP & UDP and calculate checksums for each of these.
50         #
51         if (($bytes[$base + 4] & 0xff) == 6) {
52                 &tcpcheck($base);
53         }
54
55         if (($bytes[$base + 4] & 0xff) == 17) {
56                 &udpcheck($base);
57         }
58
59         if (($bytes[$base + 4] & 0xff) == 1) {
60                 &icmpcheck($base);
61         }
62         if ($base == 0) {
63                 print "\n";
64         }
65 }
66
67 sub tcpcheck {
68         local($base) = $_[0];
69         local($hl) = $bytes[$base] / 256;
70         return if (($hl >> 4) != 4);
71         return if ($bytes[$base + 3] & 0x1fff);
72         $hl &= 0xf;
73         $hl <<= 1;
74
75         local($hs2);
76         local($hs) = 6; # TCP
77         local($len) = $bytes[$base + 1] - ($hl << 1);
78         $hs += $len;
79         $hs += $bytes[$base + 6];       # source address
80         $hs += $bytes[$base + 7];
81         $hs += $bytes[$base + 8];       # destination address
82         $hs += $bytes[$base + 9];
83         local($tcpsum) = $hs;
84
85         local($thl) = $bytes[$base + $hl + 6] >> 8;
86         $thl &= 0xf0;
87         $thl >>= 2;
88
89         $x = $bytes[$base + 1];
90         $y = ($cnt - $base) * 2;
91         $z = 0;
92         if ($bytes[$base + 1] > ($cnt - $base) * 2) {
93                 print "[cnt=$cnt base=$base]";
94                 $x = $bytes[$base + 1];
95                 $y = ($cnt - $base) * 2;
96                 $z = 1;
97         } elsif (($cnt - $base) * 2 < $hl + 20) {
98                 $x = ($cnt - $base) * 2;
99                 $y = $hl + 20;
100                 $z = 2;
101         } elsif (($cnt - $base) * 2 < $hl + $thl) {
102                 $x = ($cnt - $base) * 2;
103                 $y = $hl + $thl;
104                 $z = 3;
105         } elsif ($len < $thl) {
106                 $x = ($cnt - $base) * 2;
107                 $y = $len;
108                 $z = 4;
109         }
110
111         if ($z) {
112                 print " TCP: missing data($x $y $z) $hl";
113 #               &dump();
114                 return;
115         }
116
117         local($tcpat) = $base + $hl;
118         $hs = &dosum($tcpsum, $tcpat, $cnt);
119         if ($hs != 0) {
120                 local($osum) = $bytes[$tcpat + 8];
121                 $bytes[$base + $hl + 8] = 0;
122                 $hs2 = &dosum($tcpsum, $tcpat, $cnt);
123                 $bytes[$tcpat + 8] = $osum;
124                 printf " TCP: (%x) %x != %x", $hs, $osum, $hs2;
125         } else {
126                 print " TCP: ok ($x $y)";
127         }
128 }
129
130 sub udpcheck {
131         local($base) = $_[0];
132         local($hl) = $bytes[0] / 256;
133         return if (($hl >> 4) != 4);
134         return if ($bytes[3] & 0x1fff);
135         $hl &= 0xf;
136         $hl <<= 1;
137
138         local($hs2);
139         local($hs) = 17;        # UDP
140         local($len) = $bytes[$base + 1] - ($hl << 1);
141         $hs += $len;
142         $hs += $bytes[$base + 6];       # source address
143         $hs += $bytes[$base + 7];
144         $hs += $bytes[$base + 8];       # destination address
145         $hs += $bytes[$base + 9];
146         local($udpsum) = $hs;
147
148         if ($bytes[$base + 1] > ($cnt - $base) * 2) {
149                 print " UDP: missing data(1)";
150                 return;
151         } elsif ($bytes[$base + 1] < ($hl << 1) + 8) {
152                 print " UDP: missing data(2)";
153                 return;
154         } elsif (($cnt - $base) * 2 < ($hl << 1) + 8) {
155                 print " UDP: missing data(3)";
156                 return;
157         }
158
159         local($udpat) = $base + $hl;
160         $hs = &dosum($udpsum, $udpat, $cnt);
161         local($osum) = $bytes[$udpat + 3];
162
163         #
164         # It is valid for UDP packets to have a 0 checksum field.
165         # If it is 0, then display what it would otherwise be.
166         #
167         if ($osum == 0) {
168                 printf " UDP: => %x", $hs;
169         } elsif ($hs != 0) {
170                 $bytes[$udpat + 3] = 0;
171                 $hs2 = &dosum($udpsum, $udpat, $cnt);
172                 $bytes[$udpat + 3] = $osum;
173                 printf " UDP: (%x) %x != %x", $hs, $osum, $hs2;
174         } else {
175                 print " UDP: ok";
176         }
177 }
178
179 sub icmpcheck {
180         local($base) = $_[0];
181         local($hl) = $bytes[$base + 0] / 256;
182         return if (($hl >> 4) != 4);
183         return if ($bytes[3] & 0x1fff);
184         $hl &= 0xf;
185         $hl <<= 1;
186
187         local($hs);
188         local($hs2);
189
190         local($len) = $bytes[$base + 1] - ($hl << 1);
191
192         if ($bytes[$base + 1] > ($cnt - $base) * 2) {
193                 print " ICMP: missing data(1)";
194                 return;
195         } elsif ($bytes[$base + 1] < ($hl << 1) + 8) {
196                 print " ICMP: missing data(2)";
197                 return;
198         } elsif (($cnt - $base) * 2 < ($hl << 1) + 8) {
199                 print " ICMP: missing data(3)";
200                 return;
201         }
202
203         local($osum) = $bytes[$base + $hl + 1];
204         $bytes[$base + $hl + 1] = 0;
205         $hs2 = &dosum(0, $base + $hl, $cnt);
206         $bytes[$base + $hl + 1] = $osum;
207
208         if ($osum != $hs2) {
209                 printf " ICMP: (%x) %x != %x", $hs, $osum, $hs2;
210         } else {
211                 print " ICMP: ok";
212         }
213         if ($base == 0) {
214                 $type = $bytes[$hl] >> 8;
215                 if ($type == 3 || $type == 4 || $type == 5 ||
216                     $type == 11 || $type == 12) {
217                         &ipv4check($hl + 4);
218                 }
219         }
220 }
221
222 while ($#ARGV >= 0) {
223         open(I, "$ARGV[0]") || die $!;
224         print "--- $ARGV[0] ---\n";
225         $multi = 0;
226         while (<I>) {
227                 chop;
228                 s/#.*//g;
229
230                 #
231                 # If the first non-comment, non-empty line of input starts
232                 # with a '[', then allow the input to be a multi-line hex
233                 # string, otherwise it has to be all on one line.
234                 #
235                 if (/^\[/) {
236                         $multi=1;
237                         s/^\[[^]]*\]//g;
238
239                 }
240                 s/^ *//g;
241                 if (length == 0) {
242                         next if ($cnt == 0);
243                         &ipv4check(0);
244                         $cnt = 0;
245                         $multi = 0;
246                         next;
247                 }
248
249                 #
250                 # look for 16 bits, represented with leading 0's as required,
251                 # in hex.
252                 #
253                 s/\t/ /g;
254                 while (/^[0-9a-fA-F][0-9a-fA-F] [0-9a-fA-F][0-9a-fA-F] .*/) {
255                         s/^([0-9a-fA-F][0-9a-fA-F]) ([0-9a-fA-F][0-9a-fA-F]) (.*)/$1$2 $3/;
256                 }
257                 while (/.* [0-9a-fA-F][0-9a-fA-F] [0-9a-fA-F][0-9a-fA-F] .*/) {
258 $b=$_;
259                         s/(.*?) ([0-9a-fA-F][0-9a-fA-F]) ([0-9a-fA-F][0-9a-fA-F]) (.*)/$1 $2$3 $4/g;
260                 }
261                 if (/.* [0-9a-fA-F][0-9a-fA-F] [0-9a-fA-F][0-9a-fA-F]/) {
262 $b=$_;
263                         s/(.*?) ([0-9a-fA-F][0-9a-fA-F]) ([0-9a-fA-F][0-9a-fA-F])/$1 $2$3/g;
264                 }
265                 while (/^[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F].*/) {
266                         $x = $_;
267                         $x =~ s/([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]).*/$1/;
268                         $x =~ s/ *//g;
269                         $y = hex $x;
270                         s/[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F] *(.*)/$1/;
271                         $bytes[$cnt] = $y;
272 #print "bytes[$cnt] = $x\n";
273                         $cnt++;
274                 }
275
276                 #
277                 # Pick up stragler bytes.
278                 #
279                 if (/^[0-9a-fA-F][0-9a-fA-F]/) {
280                         $y = hex $_;
281                         $bytes[$cnt++] = $y * 256;
282                 }
283                 if ($multi == 0 && $cnt > 0) {
284                         &ipv4check(0);
285                         $cnt = 0;
286                 }
287         }
288
289         if ($cnt > 0) {
290                 &ipv4check(0);
291         }
292         close(I);
293         shift(@ARGV);
294 }