#! /usr/bin/python # # this prog was loosely ported from a similar javascript # implementation written by me earlier. In javascript # variables are 32 bits and signed, so I opted to use arrays # of 4 integers to represent each IP address. # # Python allows unlimited precision, so a different approach # might have been indicated. -- Next time... ;) # # (c)2000 Manfred Bartz # You may use this source code as per the # "Gnu General Public License (GPL)" # V1.1 Added ability to calculate the best fit subnet based on # an IP address range. # # V1.1a Made HTML tag generation a command line option (--html) # rather than assuming it from sys.stdout.isatty() # import getopt, sys, string, re # netaddr/netmask format PattAddrMask = re.compile(\ '^(\d+)\.(\d+)\.(\d+)\.(\d+)\s{0,2}/\s{0,2}(\d+)\.(\d+)\.(\d+)\.(\d+).*$') PattAddrRange = re.compile(\ '^(\d+)\.(\d+)\.(\d+)\.(\d+)\s{0,2}[-:]\s{0,2}(\d+)\.(\d+)\.(\d+)\.(\d+).*$') PattPartialNetmask = re.compile(\ '^\d+\.\d+\.\d+\.\d+/(\d+\.[\.0-9]+)[^\.\d]*$') # netaddr/masklen format PattAddrMLen = re.compile(\ '^(\d+)\.(\d+)\.(\d+)\.(\d+)/(\d+).*$') # netaddr/masklen format PattAddrOnly = re.compile(\ '^(\d+)\.(\d+)\.(\d+)\.(\d+)\D*$') NetAddr = [0,0,0,0] HostAddr = [0,0,0,0] HostAddr2 = [0,0,0,0] NetMask = [0,0,0,0] Broadcast = [0,0,0,0] FirstHost = [0,0,0,0] LastHost = [0,0,0,0] #---------------------------------------------------------------------- def RangeOk(n, min, max): if (n >= min) and (n <= max): return 1 return 0 #---------------------------------------------------------------------- def allBits0(n): r = 0 for i in range(len(n)): r = r | n[i] return r == 0 #---------------------------------------------------------------------- def allBits1(n): r = 0xFF for i in range(len(n)): r = r & n[i] return (r & 0xFF) == 0xFF #---------------------------------------------------------------------- def quitOutOfRange(s): print '%s%s bad: each number in the dotted quad must be in the range 0 to 255!%s' \ % (TagRed, s, TagNormal) sys.exit(1) #---------------------------------------------------------------------- def tellBadMask(s): print '%sNetMask bad: %s%s' % (TagRed, s, TagNormal) print #---------------------------------------------------------------------- def ParseInput(inpLine): global NetMaskBad global MaskLen global isAddrRange NetMaskBad = 0 MaskLen = 0 NxorAddr = [0,0,0,0] MatchResult = PattAddrRange.match(inpLine) if MatchResult: # print 'netaddr1/netaddr2 format' isAddrRange = 1 for i in range(4): HostAddr[i] = string.atoi(MatchResult.group(i+1)) if not RangeOk(HostAddr[i], 0, 255): quitOutOfRange('HostAddr1') for i in range(4): HostAddr2[i] = string.atoi(MatchResult.group(i+5)) if not RangeOk(HostAddr2[i], 0, 255): quitOutOfRange('HostAddr2') NxorAddr[i] = ~ (HostAddr[i] ^ HostAddr2[i]) i = 0 done = 0 while i < 4: bitmask = 0x80 for b in range(8): if not done: if NxorAddr[i] & bitmask: MaskLen = MaskLen + 1 else: done = 1 bitmask = bitmask >> 1 i = i + 1 else: MatchResult = PattAddrMask.match(inpLine) if MatchResult: # print 'netaddr/netmask format' for i in range(4): HostAddr[i] = string.atoi(MatchResult.group(i+1)) if not RangeOk(HostAddr[i], 0, 255): quitOutOfRange('HostAddr') for i in range(4): NetMask[i] = string.atoi(MatchResult.group(i+5)) if not RangeOk(NetMask[i], 0, 255): quitOutOfRange('NetMask') i = 0 done = 0 while i < 4: bitmask = 0x80 for b in range(8): if not done: if NetMask[i] & bitmask: MaskLen = MaskLen + 1 else: done = 1 else: if NetMask[i] & bitmask: NetMaskBad = 1 bitmask = bitmask >> 1 i = i + 1 else: MatchResult = PattPartialNetmask.match(inpLine) if MatchResult: tellBadMask('"%s" is partial mask, use full mask or specify mask length' \ % MatchResult.group(1)); sys.exit(1) else: MatchResult = PattAddrMLen.match(inpLine) if MatchResult: # print 'netaddr/MaskLen format' for i in range(4): HostAddr[i] = string.atoi(MatchResult.group(i+1)) if not RangeOk(HostAddr[i], 0, 255): quitOutOfRange('HostAddr') MaskLen = string.atoi(MatchResult.group(5)) if not RangeOk(MaskLen, 0, 32): tellBadMask('must be in the range of 0 to 32 bits, set to 32'); MaskLen = 32 else: MatchResult = PattAddrOnly.match(inpLine) if MatchResult: # print 'netaddr only format' for i in range(4): HostAddr[i] = string.atoi(MatchResult.group(i+1)) if not RangeOk(HostAddr[i], 0, 255): quitOutOfRange('HostAddr') MaskLen = 8 # default is old class A if (HostAddr[0] & 0xC0) == 0x80: # old class B MaskLen = 16 print 'Assuming class B netmask\n' elif (HostAddr[0] & 0xE0) == 0xC0: # old class C MaskLen = 24 print 'Assuming class C netmask\n' elif (HostAddr[0] & 0xF0) == 0xE0: # class D (multicast) MaskLen = 4 # print 'Assuming class D netmask\n' elif (HostAddr[0] & 0xF0) == 0xF0: # class E (experimental) MaskLen = 4 # print 'Assuming class E netmask\n' else: if not (allBits0(HostAddr) or allBits1(HostAddr)): print 'Assuming class A netmask\n' else: # print 'sys.exc_type=', sys.exc_type print inpLine print 'beats me...' sys.exit(1) i = 0 n = MaskLen while n > 0: bitmask = 0x80 for b in range(8): if n > 0: NetMask[i] = NetMask[i] | bitmask n = n - 1 bitmask = bitmask >> 1 i = i + 1 #---------------------------------------------------------------------- def CalcHosts(): global NumHosts NumHosts = 0L for i in range(4): NetAddr[i] = HostAddr[i] & NetMask[i] Broadcast[i] = HostAddr[i] | (~NetMask[i] & 0xFF) if (RangeOk(MaskLen, 0, 30)): for i in range(4): FirstHost[i] = NetAddr[i] LastHost[i] = Broadcast[i] FirstHost[3] = FirstHost[3] + 1 LastHost[3] = LastHost[3] - 1 NumHosts = (0x01L << (32 - MaskLen)) - 2L #---------------------------------------------------------------------- def FormatDecBinHex(n): global dottedQuad global binString global hexString dottedQuad = '%d.%d.%d.%d' % (n[0], n[1], n[2], n[3]) hexString = '0x%02X%02X%02X%02X' % (n[0], n[1], n[2], n[3]) binString = '' i = 0 m = 0 bitmask = 0x80 # set color for mask bits binString = binString + TagDarkBlue while i < 4: while bitmask: m = m + 1 if m > MaskLen: break if n[i] & bitmask: binString = binString + '1' else: binString = binString + '0' bitmask = bitmask >> 1 if m > MaskLen: break if not bitmask: bitmask = 0x80 i = i + 1 if (i < 4): binString = binString + '.' # set color for host bits binString = binString + TagNormal + TagDarkRed while i < 4: while bitmask: if n[i] & bitmask: binString = binString + '1' else: binString = binString + '0' bitmask = bitmask >> 1 if not bitmask: bitmask = 0x80 i = i + 1 if (i < 4): binString = binString + '.' # restore default color binString = binString + TagNormal #---------------------------------------------------------------------- def PrintNetworkAddress(): global NumHosts if NetMaskBad: tellBadMask('must be consecutive ones starting at MSB') FormatDecBinHex(NetAddr) AddrAndMask = '%s/%s' % (dottedQuad, MaskLen) # print '%-18.18s' % (AddrAndMask) print AddrAndMask def PrintInfo(): global NumHosts if NetMaskBad: tellBadMask('must be consecutive ones starting at MSB') FormatDecBinHex(HostAddr) if not isAddrRange: print '%sHost%sAddr %-18.18s %s %s' \ % (TagDarkRed+TagBold, TagUnBold+TagNormal, dottedQuad, binString, hexString) else: print '%sAddress1%s %-18.18s %s %s' \ % (TagBold, TagUnBold, dottedQuad, binString, hexString) if allBits1(HostAddr): print '%sThis is the global broadcast address!%s' \ % (TagRed, TagNormal) return if isAddrRange: FormatDecBinHex(HostAddr2) print '%sAddress2%s %-18.18s %s %s' \ % (TagBold, TagUnBold, dottedQuad, binString, hexString) FormatDecBinHex(NetMask) print '%sNet%sMask %-18.18s %s %s' \ % (TagDarkBlue+TagBold, TagUnBold+TagNormal, dottedQuad, binString, hexString) if allBits0(HostAddr) and allBits0(NetMask): print '%sThis is the entire Internet!%s' % (TagRed, TagNormal) print FormatDecBinHex(NetAddr) AddrAndMask = '%s/%s' % (dottedQuad, MaskLen) print 'NetAddr %-18.18s %s %s' % (AddrAndMask, binString, hexString) if not NetMaskBad: if (RangeOk(MaskLen, 0, 30)): FormatDecBinHex(FirstHost) print 'First Host %-18.18s %s %s' % (dottedQuad, binString, hexString) FormatDecBinHex(LastHost) print 'Last Host %-18.18s %s %s' % (dottedQuad, binString, hexString) if (RangeOk(MaskLen, 0, 31)): FormatDecBinHex(Broadcast) print 'Broadcast %-18.18s %s %s' % (dottedQuad, binString, hexString) if (RangeOk(MaskLen, 0, 30)): print 'N Hosts %s' % string.replace(str(NumHosts),"L","",1) print HostPtr = '%d.%d.%d.%d.in-addr.arpa.' \ % (HostAddr[3], HostAddr[2], HostAddr[1], HostAddr[0]) print '%-30.30s IN PTR' % HostPtr if not NetMaskBad: NetPtr = '%d.%d.%d.%d.in-addr.arpa.' \ % (NetAddr[3], NetAddr[2], NetAddr[1], NetAddr[0]) print '%-30.30s IN PTR' % NetPtr print if (NetAddr[0] & 0xF0) == 0xE0: print 'Note: Network address is class D (multicast)' elif (NetAddr[0] & 0xF0) == 0xF0: print 'Note: Network address is class E (experimental)' ## if (NetAddr[0] & 0xF0) >= 0xE0 and MaskLen != 4: ## print ' %sThe mask length should possibly be 4%s' \ ## % (TagRed, TagNormal) #---------------------------------------------------------------------- # main prog #print 'NetCalc V1.1a' OptionList, ArgList = getopt.getopt(sys.argv[1:], '', ['html', 'debug','network']) # any args? if len(ArgList) < 1: print 'Need an argument...' sys.exit(1) # any options? isHTML = 0 isDebug = 0 isNetWorkAddress = 0 for Option, Value in OptionList: if Option == '--html': isHTML = 1 if Option == '--debug': isDebug = 1 if Option == '--network': isNetWorkAddress = 1 # init if isHTML: TagBlack = "" TagDarkBlue= "" TagDarkRed = "" TagRed = "" TagNormal = "" TagBold = "" TagUnBold = "" else: TagBlack = "" TagDarkBlue= "" TagDarkRed = "" TagRed = "" TagNormal = "" TagBold = "" TagUnBold = "" isAddrRange = 0 # action ParseInput(ArgList[0]) CalcHosts() if isNetWorkAddress: PrintNetworkAddress() else: PrintInfo() sys.exit(0)