Sync usage with man page.
[netbsd-mini2440.git] / dist / ipf / test / vfycksum.pl
blobb3a20be0cf24f3093ca6fa4d2d8547c716f7cc6e
3 # validate the IPv4 header checksum.
4 # $bytes[] is an array of 16bit values, with $cnt elements in the array.
6 sub dump {
7 print "\n";
8 for ($i = 0; $i < $#bytes; $i++) {
9 printf "%04x ", $bytes[$i];
11 print "\n";
14 sub dosum {
15 local($seed) = $_[0];
16 local($start) = $_[1];
17 local($max) = $_[2];
18 local($idx) = $start;
19 local($lsum) = $seed;
21 for ($idx = $start, $lsum = $seed; $idx < $max; $idx++) {
22 $lsum += $bytes[$idx];
24 $lsum = ($lsum & 0xffff) + ($lsum >> 16);
25 $lsum = ~$lsum & 0xffff;
26 return $lsum;
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
36 $hs = &dosum(0, $base, $base + $hl);
37 $osum = $bytes[$base + 5];
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 ";
49 # Recognise TCP & UDP and calculate checksums for each of these.
51 if (($bytes[$base + 4] & 0xff) == 6) {
52 &tcpcheck($base);
55 if (($bytes[$base + 4] & 0xff) == 17) {
56 &udpcheck($base);
59 if (($bytes[$base + 4] & 0xff) == 1) {
60 &icmpcheck($base);
62 if ($base == 0) {
63 print "\n";
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;
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;
85 local($thl) = $bytes[$base + $hl + 6] >> 8;
86 $thl &= 0xf0;
87 $thl >>= 2;
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;
111 if ($z) {
112 print " TCP: missing data($x $y $z) $hl";
113 # &dump();
114 return;
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)";
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;
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;
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;
159 local($udpat) = $base + $hl;
160 $hs = &dosum($udpsum, $udpat, $cnt);
161 local($osum) = $bytes[$udpat + 3];
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.
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";
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;
187 local($hs);
188 local($hs2);
190 local($len) = $bytes[$base + 1] - ($hl << 1);
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;
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;
208 if ($osum != $hs2) {
209 printf " ICMP: (%x) %x != %x", $hs, $osum, $hs2;
210 } else {
211 print " ICMP: ok";
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);
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;
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.
235 if (/^\[/) {
236 $multi=1;
237 s/^\[[^]]*\]//g;
240 s/^ *//g;
241 if (length == 0) {
242 next if ($cnt == 0);
243 &ipv4check(0);
244 $cnt = 0;
245 $multi = 0;
246 next;
250 # look for 16 bits, represented with leading 0's as required,
251 # in hex.
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/;
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;
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;
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++;
277 # Pick up stragler bytes.
279 if (/^[0-9a-fA-F][0-9a-fA-F]/) {
280 $y = hex $_;
281 $bytes[$cnt++] = $y * 256;
283 if ($multi == 0 && $cnt > 0) {
284 &ipv4check(0);
285 $cnt = 0;
289 if ($cnt > 0) {
290 &ipv4check(0);
292 close(I);
293 shift(@ARGV);