#!/usr/bin/perl -w ######################################################################### # # A perl CGI program to display a number in various base formats. # # v1.0, Sep 14 2002 # v1.1, Sep 16 2002 added CIDR subnet stuff # v1.2, Sep 21 2002 partial IP addresses like 10. expand to 10.0.0.0 # v1.3, Sep 21 2002 in CIDR, added Broadcast, removed 0 and 255 from hosts # v1.4, sep 27 2002 added 255.255.xx style display for Mask. # v1.5, oct 12 put 0 and 255 back in. # # Copyright (c) 2002 Jim Mahoney (mahoney@marlboro.edu), Marlboro College. # All rights reserved. This program is free software; you can # redistribute and/or modify it under the same terms as perl itself. # ########################################################################## use strict; use CGI qw(:standard); my $number = param("number"); # inputs from cgi form or URL my $explain = param("explain"); print header, start_html(-title => 'Base Conversion and Subnet Tool'), start_form, "

Base Conversion and Subnet Tool

", "Pick a number.   ", textfield( -name => "number", size => 48 ), "   Help", end_form, $number ? response_as_html($number) : "", $explain ? explanation_html() : "", footer_html(), end_html, ; # ================================================================== # Return as html an analysis of the user defined number $input, # which may be in of a variety of formats # and which may include a subnet mask (i.e. 10 or 0xEE or 12.6.2/23) # See sub explanation_html for the allowed format details. sub response_as_html { my ($input) = @_; my ($maskOnes) = ($input =~ m{/(\d\d?)$}g ); # Look for xxxxxx/dd # where dd = subnet mask $input =~ s{/\d\d?$}{}; # Remove /dd from input. if ( $input =~ m/^\d.*\./ ) { # Starts with a digit and has a period? my @nums = split /\./, $input; if (@nums>4) { return "
Oops: your number looks like it might be in IP format (i.e. 10.0.0.0) but has too many periods.\n"; } push(@nums,0) while @nums<4; $input = $nums[3] + $nums[2]*256.0 + $nums[1]*256.0**2 + $nums[0]*256.0**3; } else { my $original= "".$input; # Make sure it's a string. $input = eval($original); # Convert things like "0x44" to numbers. $input = int( $input + 0.49 ); # Round off fractions to integer. } my $maskHtml = getMaskHtml($maskOnes, $input); if ( ($input>4294967295.0) or ($input<0.0) ) { return "
Your number is '$input'.
Oops: only integers between 0 and 4294967295 (i.e. 32 bits) are allowed. "; } else { return "
\n"
        . " Base 10: " . "    " . underBars(sprintf("%u",$input),3) ."\n"
        . " Octal:   " . "0___" . sprintf( "%o",$input)              ."\n"
        . " Hex:     " . "0x__" . underBars(sprintf("%x",$input),2)  ."\n"
        . " IP:      " . "    " . asIP($input)                       ."\n"
        . " Binary:  " . "0b__" . underBars( asBinary($input), 8)    ."\n"
        .   $maskHtml
        . "
\n"; } } # ---------------------------------------------------------- # Input: $maskOnes = number of subnet mask ones, i.e. 22 # $input = IP address # Output: html formatted description of CIDR subnet and addresses. sub getMaskHtml { my ($maskOnes, $input) = @_; return "" unless $maskOnes; $maskOnes = int($maskOnes + 0.49); if ($maskOnes>32) { return "\nOops: Subnet mask '\\$maskOnes' is larger than 32. \n"; } my $numAddr = 2**(32-$maskOnes); my $mask = 2**32 - $numAddr; my $network = $mask & $input; # bitwise "and" return "\n" . " Mask: " . " " . asIP($mask) . "\n" . " = " . "0b__" . underBars( asBinary($mask), 8) . "\n" . " Subnet: " . " " . asIP($network) . "\n" . " = " . "0b__" . underBars( asBinary($network), 8) . "\n\n" . " The number of addresses is 2**(32-$maskOnes) = ".$numAddr . "\n" . " which go from " . asIP($network) . " up to " . asIP($network+$numAddr-1) . " .\n" . " (The lowest is the network address, \n" . " and the highest is the broadcast address.)\n"; } # ---------------------------------------------------------- # Convert a number like 201778690 # to a string like 1100000001101110011000000010 sub asBinary { my ($number) = @_; my $result = ""; my $count = 32; while ($number or ($count>0)) { my $nextBit = $number % 2; $number = ($number - $nextBit) / 2; $result = ($nextBit or "0") . $result; $count--; } return $result; } # --------------------------------------------------------- # Convert a number like 201778690 to a string like 12.6.230.2 sub asIP { my ($number) = @_; my $result = ""; my $count = 4; while ($number or ($count>0)) { my $nextByte = $number % 2**8; $number = ($number - $nextByte) / 2**8; $result = ($nextByte or "0") . '.' . $result; $count--; } $result =~ s/.$//; # Remove trailing ".", since the while loop # constructs the result as "xxx.xxx.xxx.xxx.". return $result; } # --------------------------------------------------------- # Convert a string like 12345678 to a string like 12_345_678 for readability. # The number of digits to group together is passed as the parameter $n. sub underBars { my ($string, $n) = @_; return $string unless $n; my @digits = split //, $string; my @underbars; while (@digits) { unshift( @underbars, pop(@digits)) for 1..$n; unshift( @underbars, "_") if @digits; } return join("", @underbars); } # --------------------------------------------------------- # Return as html an explanation of what this script does. sub explanation_html { return qq{ Enter a number in any of the following formats, then hit return to see that number displayed in all the others.
   Base 10                201_778_690
   Octal  (Base  8)    0__1401563002                            (leading zero)
   Hex    (Base 16)    0x_0C_06_E6_02                           (leading 0x)
   IP                     12.6.230.2                            (periods)
   Binary (Base  2)    0b_00001100_00000110_11100110_00000010   (leading 0b)
 
The underbar character ("_") in all of these is entirely optional and included for legibility only.

To see a CIDR subnet mask applied to your number, append a slash and a number between 1 and 32, i.e. 12.6.230.2/22 .

Numbers in IP format (i.e. 12.6.230.2) must begin with a digit and contain either one, two, or three periods.
Partial IP addresses like 10. or 10.2 will be expanded by appending zeros and periods at the right end as needed.

The number may be passed in the scipt URL as ?number= , i.e. baseConvert.cgi?number=10.2.1/22 .

So there you are. }; } # --------------------------------------------------------- sub footer_html { return qq{


Jim Mahoney <mahoney\@marlboro.edu>
source code
}; }