summaryrefslogtreecommitdiffstats
path: root/test/vfycksum.pl
diff options
context:
space:
mode:
Diffstat (limited to 'test/vfycksum.pl')
-rwxr-xr-xtest/vfycksum.pl294
1 files changed, 294 insertions, 0 deletions
diff --git a/test/vfycksum.pl b/test/vfycksum.pl
new file mode 100755
index 0000000..b3a20be
--- /dev/null
+++ b/test/vfycksum.pl
@@ -0,0 +1,294 @@
+
+#
+# validate the IPv4 header checksum.
+# $bytes[] is an array of 16bit values, with $cnt elements in the array.
+#
+sub dump {
+ print "\n";
+ for ($i = 0; $i < $#bytes; $i++) {
+ printf "%04x ", $bytes[$i];
+ }
+ print "\n";
+}
+
+sub dosum {
+ local($seed) = $_[0];
+ local($start) = $_[1];
+ local($max) = $_[2];
+ local($idx) = $start;
+ local($lsum) = $seed;
+
+ for ($idx = $start, $lsum = $seed; $idx < $max; $idx++) {
+ $lsum += $bytes[$idx];
+ }
+ $lsum = ($lsum & 0xffff) + ($lsum >> 16);
+ $lsum = ~$lsum & 0xffff;
+ return $lsum;
+}
+
+sub ipv4check {
+ local($base) = $_[0];
+ $hl = $bytes[$base] / 256;
+ return if (($hl >> 4) != 4); # IPv4 ?
+ $hl &= 0xf;
+ $hl <<= 1; # get the header length in 16bit words
+
+ $hs = &dosum(0, $base, $base + $hl);
+ $osum = $bytes[$base + 5];
+
+ if ($hs != 0) {
+ $bytes[$base + 5] = 0;
+ $hs2 = &dosum(0, $base, $base + $hl);
+ $bytes[$base + 5] = $osum;
+ printf " IP: ($hl,%x) %x != %x", $hs, $osum, $hs2;
+ } else {
+ print " IP($base): ok ";
+ }
+
+ #
+ # Recognise TCP & UDP and calculate checksums for each of these.
+ #
+ if (($bytes[$base + 4] & 0xff) == 6) {
+ &tcpcheck($base);
+ }
+
+ if (($bytes[$base + 4] & 0xff) == 17) {
+ &udpcheck($base);
+ }
+
+ if (($bytes[$base + 4] & 0xff) == 1) {
+ &icmpcheck($base);
+ }
+ if ($base == 0) {
+ print "\n";
+ }
+}
+
+sub tcpcheck {
+ local($base) = $_[0];
+ local($hl) = $bytes[$base] / 256;
+ return if (($hl >> 4) != 4);
+ return if ($bytes[$base + 3] & 0x1fff);
+ $hl &= 0xf;
+ $hl <<= 1;
+
+ local($hs2);
+ local($hs) = 6; # TCP
+ local($len) = $bytes[$base + 1] - ($hl << 1);
+ $hs += $len;
+ $hs += $bytes[$base + 6]; # source address
+ $hs += $bytes[$base + 7];
+ $hs += $bytes[$base + 8]; # destination address
+ $hs += $bytes[$base + 9];
+ local($tcpsum) = $hs;
+
+ local($thl) = $bytes[$base + $hl + 6] >> 8;
+ $thl &= 0xf0;
+ $thl >>= 2;
+
+ $x = $bytes[$base + 1];
+ $y = ($cnt - $base) * 2;
+ $z = 0;
+ if ($bytes[$base + 1] > ($cnt - $base) * 2) {
+ print "[cnt=$cnt base=$base]";
+ $x = $bytes[$base + 1];
+ $y = ($cnt - $base) * 2;
+ $z = 1;
+ } elsif (($cnt - $base) * 2 < $hl + 20) {
+ $x = ($cnt - $base) * 2;
+ $y = $hl + 20;
+ $z = 2;
+ } elsif (($cnt - $base) * 2 < $hl + $thl) {
+ $x = ($cnt - $base) * 2;
+ $y = $hl + $thl;
+ $z = 3;
+ } elsif ($len < $thl) {
+ $x = ($cnt - $base) * 2;
+ $y = $len;
+ $z = 4;
+ }
+
+ if ($z) {
+ print " TCP: missing data($x $y $z) $hl";
+# &dump();
+ return;
+ }
+
+ local($tcpat) = $base + $hl;
+ $hs = &dosum($tcpsum, $tcpat, $cnt);
+ if ($hs != 0) {
+ local($osum) = $bytes[$tcpat + 8];
+ $bytes[$base + $hl + 8] = 0;
+ $hs2 = &dosum($tcpsum, $tcpat, $cnt);
+ $bytes[$tcpat + 8] = $osum;
+ printf " TCP: (%x) %x != %x", $hs, $osum, $hs2;
+ } else {
+ print " TCP: ok ($x $y)";
+ }
+}
+
+sub udpcheck {
+ local($base) = $_[0];
+ local($hl) = $bytes[0] / 256;
+ return if (($hl >> 4) != 4);
+ return if ($bytes[3] & 0x1fff);
+ $hl &= 0xf;
+ $hl <<= 1;
+
+ local($hs2);
+ local($hs) = 17; # UDP
+ local($len) = $bytes[$base + 1] - ($hl << 1);
+ $hs += $len;
+ $hs += $bytes[$base + 6]; # source address
+ $hs += $bytes[$base + 7];
+ $hs += $bytes[$base + 8]; # destination address
+ $hs += $bytes[$base + 9];
+ local($udpsum) = $hs;
+
+ if ($bytes[$base + 1] > ($cnt - $base) * 2) {
+ print " UDP: missing data(1)";
+ return;
+ } elsif ($bytes[$base + 1] < ($hl << 1) + 8) {
+ print " UDP: missing data(2)";
+ return;
+ } elsif (($cnt - $base) * 2 < ($hl << 1) + 8) {
+ print " UDP: missing data(3)";
+ return;
+ }
+
+ local($udpat) = $base + $hl;
+ $hs = &dosum($udpsum, $udpat, $cnt);
+ local($osum) = $bytes[$udpat + 3];
+
+ #
+ # It is valid for UDP packets to have a 0 checksum field.
+ # If it is 0, then display what it would otherwise be.
+ #
+ if ($osum == 0) {
+ printf " UDP: => %x", $hs;
+ } elsif ($hs != 0) {
+ $bytes[$udpat + 3] = 0;
+ $hs2 = &dosum($udpsum, $udpat, $cnt);
+ $bytes[$udpat + 3] = $osum;
+ printf " UDP: (%x) %x != %x", $hs, $osum, $hs2;
+ } else {
+ print " UDP: ok";
+ }
+}
+
+sub icmpcheck {
+ local($base) = $_[0];
+ local($hl) = $bytes[$base + 0] / 256;
+ return if (($hl >> 4) != 4);
+ return if ($bytes[3] & 0x1fff);
+ $hl &= 0xf;
+ $hl <<= 1;
+
+ local($hs);
+ local($hs2);
+
+ local($len) = $bytes[$base + 1] - ($hl << 1);
+
+ if ($bytes[$base + 1] > ($cnt - $base) * 2) {
+ print " ICMP: missing data(1)";
+ return;
+ } elsif ($bytes[$base + 1] < ($hl << 1) + 8) {
+ print " ICMP: missing data(2)";
+ return;
+ } elsif (($cnt - $base) * 2 < ($hl << 1) + 8) {
+ print " ICMP: missing data(3)";
+ return;
+ }
+
+ local($osum) = $bytes[$base + $hl + 1];
+ $bytes[$base + $hl + 1] = 0;
+ $hs2 = &dosum(0, $base + $hl, $cnt);
+ $bytes[$base + $hl + 1] = $osum;
+
+ if ($osum != $hs2) {
+ printf " ICMP: (%x) %x != %x", $hs, $osum, $hs2;
+ } else {
+ print " ICMP: ok";
+ }
+ if ($base == 0) {
+ $type = $bytes[$hl] >> 8;
+ if ($type == 3 || $type == 4 || $type == 5 ||
+ $type == 11 || $type == 12) {
+ &ipv4check($hl + 4);
+ }
+ }
+}
+
+while ($#ARGV >= 0) {
+ open(I, "$ARGV[0]") || die $!;
+ print "--- $ARGV[0] ---\n";
+ $multi = 0;
+ while (<I>) {
+ chop;
+ s/#.*//g;
+
+ #
+ # If the first non-comment, non-empty line of input starts
+ # with a '[', then allow the input to be a multi-line hex
+ # string, otherwise it has to be all on one line.
+ #
+ if (/^\[/) {
+ $multi=1;
+ s/^\[[^]]*\]//g;
+
+ }
+ s/^ *//g;
+ if (length == 0) {
+ next if ($cnt == 0);
+ &ipv4check(0);
+ $cnt = 0;
+ $multi = 0;
+ next;
+ }
+
+ #
+ # look for 16 bits, represented with leading 0's as required,
+ # in hex.
+ #
+ s/\t/ /g;
+ while (/^[0-9a-fA-F][0-9a-fA-F] [0-9a-fA-F][0-9a-fA-F] .*/) {
+ s/^([0-9a-fA-F][0-9a-fA-F]) ([0-9a-fA-F][0-9a-fA-F]) (.*)/$1$2 $3/;
+ }
+ while (/.* [0-9a-fA-F][0-9a-fA-F] [0-9a-fA-F][0-9a-fA-F] .*/) {
+$b=$_;
+ s/(.*?) ([0-9a-fA-F][0-9a-fA-F]) ([0-9a-fA-F][0-9a-fA-F]) (.*)/$1 $2$3 $4/g;
+ }
+ if (/.* [0-9a-fA-F][0-9a-fA-F] [0-9a-fA-F][0-9a-fA-F]/) {
+$b=$_;
+ s/(.*?) ([0-9a-fA-F][0-9a-fA-F]) ([0-9a-fA-F][0-9a-fA-F])/$1 $2$3/g;
+ }
+ while (/^[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F].*/) {
+ $x = $_;
+ $x =~ s/([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]).*/$1/;
+ $x =~ s/ *//g;
+ $y = hex $x;
+ s/[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F] *(.*)/$1/;
+ $bytes[$cnt] = $y;
+#print "bytes[$cnt] = $x\n";
+ $cnt++;
+ }
+
+ #
+ # Pick up stragler bytes.
+ #
+ if (/^[0-9a-fA-F][0-9a-fA-F]/) {
+ $y = hex $_;
+ $bytes[$cnt++] = $y * 256;
+ }
+ if ($multi == 0 && $cnt > 0) {
+ &ipv4check(0);
+ $cnt = 0;
+ }
+ }
+
+ if ($cnt > 0) {
+ &ipv4check(0);
+ }
+ close(I);
+ shift(@ARGV);
+}
OpenPOWER on IntegriCloud