Subnetting Quiz

Please read my article for some background on this web-based quiz. You may be also be interested in reading the source. If you enjoy this quiz, please leave me a comment. Have fun!
ulong = $ulong; } function getOctets() { $array = unpack("C4oct", $this->ulong); return array($array['oct1'], $array['oct2'], $array['oct3'], $array['oct4']); } function getNetwork($netmask) { return new IP($this->ulong & $netmask->ulong); } function getBroadcast($netmask) { $network = $this->getNetwork($netmask); return new IP($network->ulong | ~$netmask->ulong); } function toDottedDecimalString() { list($oct1, $oct2, $oct3, $oct4) = $this->getOctets(); return "${oct1}.${oct2}.${oct3}.${oct4}"; } function toHexString() { return "0x" . bin2hex($this->ulong); } function toBinaryString() { // decbin can't seem to handle $this->ulong, so break it up. list($oct1, $oct2, $oct3, $oct4) = $this->getOctets(); $str = sprintf("%08d", decbin($oct1)); $str .= " " . sprintf("%08d", decbin($oct2)); $str .= " " . sprintf("%08d", decbin($oct3)); $str .= " " . sprintf("%08d", decbin($oct4)); return $str; } function toPrefixString() { // Count the bits individually, since log() doesn't // support a base arg until PHP 4.3.0 (e.g. // $n = log($this->ulong, 2). Plus it probably // couldn't handle $this->ulong anyway. $array = unpack("Nulong", $this->ulong); $ulong = $array['ulong']; $n = 0; for ($i = 0; $i < 32; $i++) { if ($ulong & (1 << $i)) { $n++; } } return "/" . $n; } } // PHP doesn't support method argument overloading, // so subclass to handle dotted decimal strings. class DottedDecimalIP extends IP { function DottedDecimalIP($str) { list($oct1, $oct2, $oct3, $oct4) = split('\.', $str); $ulong = pack("CCCC", $oct1, $oct2, $oct3, $oct4); $this->IP($ulong); } } # # form submission # if (isset($_REQUEST['network'])) { $ip = trim($_REQUEST['ip']); $netmask = trim($_REQUEST['netmask']); $networkAnswer = trim($_REQUEST['network']); $broadcastAnswer = trim($_REQUEST['broadcast']); $startTime = trim($_REQUEST['startTime']); print ""; print "\n"; $ip = new DottedDecimalIP($ip); print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; $netmask = new DottedDecimalIP($netmask); print "\n"; print ""; print "\n"; print "\n"; print "\n"; $network = $ip->getNetwork($netmask); print "\n"; print ""; print "\n"; print "\n"; print "\n"; $broadcast = $ip->getBroadcast($netmask); print "\n"; print ""; print "\n"; print "\n"; print "
IP:" . $ip->toDottedDecimalString() . "" . $ip->toBinaryString() . "
Subnet mask:"; print $netmask->toDottedDecimalString(); print "
" . $netmask->toHexString(); print "
" . $netmask->toPrefixString(); print "
" . $netmask->toBinaryString() . "
Network address:"; print $networkAnswer; print "
\n"; if ($networkAnswer != $network->toDottedDecimalString()) { print "INCORRECT!
"; print $network->toDottedDecimalString(); print "
"; } else { print "CORRECT!"; } print "
" . $network->toBinaryString() . "
Broadcast address:"; print $broadcastAnswer; print "
\n"; if ($broadcastAnswer != $broadcast->toDottedDecimalString()) { print "INCORRECT!
"; print $broadcast->toDottedDecimalString(); print "
"; } else { print "CORRECT!"; } print "
" . $broadcast->toBinaryString() . "
"; $timeTook = time() - $startTime; if ($timeTook > (60 * 60)) { $timeTook /= (60 * 60); $units = "hours"; } elseif ($timeTook > 60) { $timeTook /= 60; $units = "minutes"; } else { $units = "seconds"; } $timeTook = round($timeTook, 1); print "You answered in: " . $timeTook . " " . $units . ".\n"; print "
\n"; } # My PHP install on Solaris is segmentation faulting on every # call to pow()! function safePow($base, $exp) { $result = 1; while ($exp-- > 0) { $result *= $base; } return $result; } # # Generate a "sane" subnet mask: # - not: 0.0.0.0, 128.0.0.0, 255.255.255.255, 255.255.255.254 # function generateMask() { $ct = 10; # infinite loop prevention while ($ct-- > 0) { $oct1 = $oct2 = $oct3 = $oct4 = 255; $which = rand(1,4); $special_oct = 256 - safePow(2, rand(0,8)); if ($which == 1) { $oct1 = $special_oct; $oct2 = $oct3 = $oct4 = 0; } elseif ($which == 2) { $oct2 = $special_oct; $oct3 = $oct4 = 0; } elseif ($which == 3) { $oct3 = $special_oct; $oct4 = 0; } elseif ($which == 4) { $oct4 = $special_oct; } $netmaskString = "${oct1}.${oct2}.${oct3}.${oct4}"; # sanity check if ($netmaskString != "0.0.0.0" && $netmaskString != "128.0.0.0" && $netmaskString != "255.255.255.255" && $netmaskString != "255.255.255.254") { # good netmask break; } } return new DottedDecimalIP($netmaskString); } # # Generate a "sane" IP: # - Class A, B, or C (i.e. first octet < 224) # - resulting network address is not 0.0.0.0 # - resulting broadcast address is not 255.255.255.255 # - IP address is not the same as the network or broadcast address # function generateIP($netmask) { $ct = 10; # infinite loop prevention while ($ct-- > 0) { $oct1 = rand(0,255); $oct2 = rand(0,255); $oct3 = rand(0,255); $oct4 = rand(0,255); $ipString = join('.', array($oct1, $oct2, $oct3, $oct4)); $ip = new DottedDecimalIP($ipString); # sanity check $network = $ip->getNetwork($netmask); $broadcast = $ip->getBroadcast($netmask); $networkString = $network->toDottedDecimalString(); $broadcastString = $broadcast->toDottedDecimalString(); if ($oct1 < 224 && $networkString != "0.0.0.0" && $broadcastString != "255.255.255.255" && $ipString != $networkString && $ipString != $broadcastString) { # good IP break; } } return $ip; } $netmask = generateMask(); $ip = generateIP($netmask); print "
\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; # easy mode always uses dotted decimal netmasks $which = 1; if (isset($_REQUEST['advancedSubnets'])) { $which = rand(1,3); } if ($which == 1) { $showNetmask = $netmask->toDottedDecimalString(); } elseif ($which == 2) { $showNetmask = $netmask->toHexString(); } elseif ($which == 3) { $showNetmask = $netmask->toPrefixString(); } print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "
IP:" . $ip->toDottedDecimalString() . "
Subnet mask:$showNetmask
Network address:
Broadcast address:
\n"; print "\n"; print "\n"; print " Advanced subnets\n"; print "toDottedDecimalString() . "\">\n"; print "toDottedDecimalString() . "\">\n"; print "\n"; print "
\n"; ?>