10 Replies - 6567 Views - Last Post: 10 August 2012 - 06:41 PM Rate Topic: -----

#1 chickensevil  Icon User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 9
  • Joined: 28-July 12

IP Range to Proper Subnetting - Not quite there

Posted 28 July 2012 - 09:28 PM

So I am writing a much larger program and this is just one piece out of it, but basically I have a list of IP ranges, and need to turn them into their proper subnets. Unfortunately these lists are not placed in their proper subnets to begin with, so here I am trying to essentially replicate the results of a site like http://ip2cidr.com/. I pulled this straight from my code so I tried to adapt values which you could then replicate the results yourself. There are two functions which I call in the shorter code I did not include (if someone would like them I can post just saving space here and know there are plenty of resources on the net already for those). These are "ConvertDecimalToIP()" and "ConvertMaskToCIDR()". both are technically uneccessary to run the core calculations, and are there to give a bit more perspective on the bigger program.

So here goes the though process: Basically if you input say 192 hosts and subtract 128 you get 64 so 128 is a proper network, and now you have 64 left over for further subnetting. Just run again with new value to continue retrieving the remainders.

Modulous division will determine if the numbers are divisible by their respective octets. If any remainder is found then the number is greater than that larger octet and will need to remove out the lower value first. Simply put modulous division until 0 found or value is less than 256.
(1st octet ignored, 2nd octet > 65536, 3rd octet > 256, 4th octet <= 256)
ex: 22184 % 65536 = 24576 % 256 = 0 -> so third octet
The program has a logic error in that if the given range encompasses a lower CIDR then a higher, then a lower, ex 352h SHOULD be 64, 256, 32 which would be a range like this:
10.0.0.192 - 10.0.2.31 -> 10.0.0.192/26, 10.0.1.0/24, 10.0.2.0/27
instead this will churn out:
10.0.0.192/26, 10.0.1.0/27, 10.0.1.32/27, 10.0.1.64/27, 10.0.1.96/27...
10.0.1.224/27, 10.0.2.0/27
So all ranges are valid, they are just not represented in their lowest form


Each of the nested functions are for calculating the subnet within that block. process is divide the IP by exponents of two up to 256 (which is 0), this tells you all the possible subnets which are legal for that IP. Then take the number of hosts 1 - 256 to tell you how many hosts fit in that range.


v = 352
sIP = '10.0.0.192'
sDec = 83886272
eDec = 0
r = ''
mask = ''
while v > 0:
    #need to accomodate non-CIDR networks
    b = GetHostRemainder(sDec, v)
    #gets the nearest whole network
    v -= b
    #calculate sDec and eDec
    eDec = sDec + v - 1
    #get mask and route
    if v != '1':
        #anything but a /32 should go here
        mask = ConvertDecimalToIP(str(v - 1))
        r = sIP + '/' + ConvertMaskToCIDR(mask)
    else:
        #/32 here, has special entry in ACL
        mask = ''
        r = sIP
    #calculate eIP
    eIP = ConvertDecimalToIP(eDec)
    #save data to row[] and append to route[]
    row = [sIP, eIP, mask, r, sDec, eDec,]
    route.append(row)
    row = []
    #get next v if b has anything left over
    if b == 0:
        #no left overs, all in proper subnet
        v = 0
    else:
        #hosts remaining, move start IP past range covered
        sIP = ConvertDecimalToIP(str(sDec + v))
        #move b into v and run again.
        v = b


def GetHostRemainder(decIP, h):
    #input  int decIP is the decimal IP of the first address in a range
    #       int v is the number of hosts(IPs) in a provided range
    #output b is the remaining number of hosts minus a proper subnet
    #get the regular notation of the IP address into a list
    ip = [decIP/256/65536, (decIP/65536)%256,(decIP/256)%256, decIP%256]
    def CalcFourth(v):
        b = 0
        if ip[3] % 2 == 0:
            if ip[3] % 4 == 0:
                if ip[3] % 8 == 0:
                    if ip[3] % 16 == 0:
                        if ip[3] % 32 == 0:
                            if ip[3] % 64 == 0:
                                if ip[3] % 128 == 0:
                                    if ip[3] % 256 == 0:
                                        #ip is 0 since 0/x = 0 special condition
                                        if v == 256:
                                            mh = 256
                                        elif v >= 128:
                                            mh = 128
                                        elif v >= 64:
                                            mh = 64
                                        elif v >= 32:
                                            mh = 32
                                        elif v >= 16:
                                            mh = 16
                                        elif v >= 8:
                                            mh = 8
                                        elif v >= 4:
                                            mh = 4
                                        elif v >= 2:
                                            mh = 2
                                        else:
                                            mh = v
                                    else:
                                        #ip is 128
                                        if v >= 128:
                                            mh = 128
                                        elif v >= 64:
                                            mh = 64
                                        elif v >= 32:
                                            mh = 32
                                        elif v >= 16:
                                            mh = 16
                                        elif v >= 8:
                                            mh = 8
                                        elif v >= 4:
                                            mh = 4
                                        elif v >= 2:
                                            mh = 2
                                        else:
                                            mh = v
                                else:
                                    #ip is multiple of 64
                                    if v >= 64:
                                        mh = 64
                                    elif v >= 32:
                                        mh = 32
                                    elif v >= 16:
                                        mh = 16
                                    elif v >= 8:
                                        mh = 8
                                    elif v >= 4:
                                        mh = 4
                                    elif v >= 2:
                                        mh = 2
                                    else:
                                        mh = v
                            else:
                                #ip is multiple of 32
                                if v >= 32:
                                    mh = 32
                                elif v >= 16:
                                    mh = 16
                                elif v >= 8:
                                    mh = 8
                                elif v >= 4:
                                    mh = 4
                                elif v >= 2:
                                    mh = 2
                                else:
                                    mh = v
                        else:
                            #ip is multiple of 16
                            if v >= 16:
                                mh = 16
                            elif v >= 8:
                                mh = 8
                            elif v >= 4:
                                mh = 4
                            elif v >= 2:
                                mh = 2
                            else:
                                mh = v
                    else:
                        #ip is multiple of 8
                        if v >= 8:
                            mh = 8
                        elif v >= 4:
                            mh = 4
                        elif v >= 2:
                            mh = 2
                        else:
                            mh = v
                else:
                    #ip is multiple of 4
                    if v >= 4:
                        mh = 4
                    elif v >= 2:
                        mh = 2
                    else:
                        mh = v
            else:
                #ip is multiple of 2
                if v >= 2:
                    mh = 2
                else:
                    mh = v
        else:
            #ip = odd number
            mh = 1
        b = mh
        return b
    def CalcThird(v):
        b = 0
        if ip[2] % 2 == 0:
            if ip[2] % 4 == 0:
                if ip[2] % 8 == 0:
                    if ip[2] % 16 == 0:
                        if ip[2] % 32 == 0:
                            if ip[2] % 64 == 0:
                                if ip[2] % 128 == 0:
                                    if ip[2] % 256 == 0:
                                        #ip is 0 since 0/x = 0 special condition
                                        v /= 256
                                        if v == 256:
                                            mh = 256
                                        elif v >= 128:
                                            mh = 128
                                        elif v >= 64:
                                            mh = 64
                                        elif v >= 32:
                                            mh = 32
                                        elif v >= 16:
                                            mh = 16
                                        elif v >= 8:
                                            mh = 8
                                        elif v >= 4:
                                            mh = 4
                                        elif v >= 2:
                                            mh = 2
                                        else:
                                            mh = v
                                    else:
                                        #ip is 128
                                        v /= 256
                                        if v >= 128:
                                            mh = 128
                                        elif v >= 64:
                                            mh = 64
                                        elif v >= 32:
                                            mh = 32
                                        elif v >= 16:
                                            mh = 16
                                        elif v >= 8:
                                            mh = 8
                                        elif v >= 4:
                                            mh = 4
                                        elif v >= 2:
                                            mh = 2
                                        else:
                                            mh = v
                                else:
                                    #ip is multiple of 64
                                    v /= 256
                                    if v >= 64:
                                        mh = 64
                                    elif v >= 32:
                                        mh = 32
                                    elif v >= 16:
                                        mh = 16
                                    elif v >= 8:
                                        mh = 8
                                    elif v >= 4:
                                        mh = 4
                                    elif v >= 2:
                                        mh = 2
                                    else:
                                        mh = v
                            else:
                                #ip is multiple of 32
                                v /= 256
                                if v >= 32:
                                    mh = 32
                                elif v >= 16:
                                    mh = 16
                                elif v >= 8:
                                    mh = 8
                                elif v >= 4:
                                    mh = 4
                                elif v >= 2:
                                    mh = 2
                                else:
                                    mh = v
                        else:
                            #ip is multiple of 16
                            v /= 256
                            if v >= 16:
                                mh = 16
                            elif v >= 8:
                                mh = 8
                            elif v >= 4:
                                mh = 4
                            elif v >= 2:
                                mh = 2
                            else:
                                mh = v
                    else:
                        #ip is multiple of 8
                        v /= 256
                        if v >= 8:
                            mh = 8
                        elif v >= 4:
                            mh = 4
                        elif v >= 2:
                            mh = 2
                        else:
                            mh = v
                else:
                    #ip is multiple of 4
                    v /= 256
                    if v >= 4:
                        mh = 4
                    elif v >= 2:
                        mh = 2
                    else:
                        mh = v
            else:
                #ip is multiple of 2
                v /= 256
                if v >= 2:
                    mh = 2
                else:
                    mh = v
        else:
            #ip = odd number
            mh = 1
        b = mh * 256
        return b
    def CalcSecond(v):
        b = 0
        if ip[1] % 2 == 0:
            if ip[1] % 4 == 0:
                if ip[1] % 8 == 0:
                    if ip[1] % 16 == 0:
                        if ip[1] % 32 == 0:
                            if ip[1] % 64 == 0:
                                if ip[1] % 128 == 0:
                                    if ip[1] % 256 == 0:
                                        #ip is 0 since 0/x = 0 special condition
                                        v /= 65536
                                        if v == 256:
                                            mh = 256
                                        elif v >= 128:
                                            mh = 128
                                        elif v >= 64:
                                            mh = 64
                                        elif v >= 32:
                                            mh = 32
                                        elif v >= 16:
                                            mh = 16
                                        elif v >= 8:
                                            mh = 8
                                        elif v >= 4:
                                            mh = 4
                                        elif v >= 2:
                                            mh = 2
                                        else:
                                            mh = v
                                    else:
                                        #ip is 128
                                        v /= 65536
                                        if v >= 128:
                                            mh = 128
                                        elif v >= 64:
                                            mh = 64
                                        elif v >= 32:
                                            mh = 32
                                        elif v >= 16:
                                            mh = 16
                                        elif v >= 8:
                                            mh = 8
                                        elif v >= 4:
                                            mh = 4
                                        elif v >= 2:
                                            mh = 2
                                        else:
                                            mh = v
                                else:
                                    #ip is multiple of 64
                                    v /= 65536
                                    if v >= 64:
                                        mh = 64
                                    elif v >= 32:
                                        mh = 32
                                    elif v >= 16:
                                        mh = 16
                                    elif v >= 8:
                                        mh = 8
                                    elif v >= 4:
                                        mh = 4
                                    elif v >= 2:
                                        mh = 2
                                    else:
                                        mh = v
                            else:
                                #ip is multiple of 32
                                v /= 65536
                                if v >= 32:
                                    mh = 32
                                elif v >= 16:
                                    mh = 16
                                elif v >= 8:
                                    mh = 8
                                elif v >= 4:
                                    mh = 4
                                elif v >= 2:
                                    mh = 2
                                else:
                                    mh = v
                        else:
                            #ip is multiple of 16
                            v /= 65536
                            if v >= 16:
                                mh = 16
                            elif v >= 8:
                                mh = 8
                            elif v >= 4:
                                mh = 4
                            elif v >= 2:
                                mh = 2
                            else:
                                mh = v
                    else:
                        #ip is multiple of 8
                        v /= 65536
                        if v >= 8:
                            mh = 8
                        elif v >= 4:
                            mh = 4
                        elif v >= 2:
                            mh = 2
                        else:
                            mh = v
                else:
                    #ip is multiple of 4
                    v /= 65536
                    if v >= 4:
                        mh = 4
                    elif v >= 2:
                        mh = 2
                    else:
                        mh = v
            else:
                #ip is multiple of 2
                v /= 65536
                if v >= 2:
                    mh = 2
                else:
                    mh = v
        else:
            #ip = odd number
            mh = 1
        b = mh * 65536
        return b
    if h <= 256:
        #Can only fill 4th octet
        b = h - CalcFourth(h)
    elif h <= 65536:
        #Possibly 3rd octet
        if h % 256 == 0:
            #definately 3rd octet
            b = h - CalcThird(h)
        else:
            #need to fill 4th octet first
            b = h - CalcFourth(h % 256)
    else:
        #Possibly 2nd octect
        if h % 65536 == 0:
            #definately 2nd octet
            b = h - CalcSecond(h)
        else:
            #need to fill at least 3rd octect first
            if (h % 65536) % 256 == 0:
                #definately 3rd octet
                b = h - CalcThird(h % 65536)
            else:
                #need to fill 4th octet first
                b = h - CalcFourth((h % 65536) % 256)
    return b



Anyway, I am down for a totally simpler concept but right now, this was the best I could figure out with no error, its just not providing the most efficient subnets, which will ultimately mean more entries in our router ACLs... If I add in the extra step to check for the condition referenced, I forsee having to add in many more lines of code. So if there is a simpler method, by all means. Why did I stick with decimal? because I didnt see any immediate benefit to going to binary. If that notion would drastically simplify the code then again, Im all ears.

I am posting this for two reasons, one its not quite where it should be (so not working all the way) and two so the internet would have some record at least one way to tackle this concept. I did tons of googling and all I got was either how to do this by hand (which its much different to tell a computer how to error check than a person) or people saying: "why are you doing this? for homework? just go to xyz site and use their tool". While I am sure I could attack their website to do what I wanted, is that really the most efficient? I think not. Basically the first part of this program pulls down the IP lists from the RIRs (ARIN, RIPE, etc)... but all it has is the start IP address and the number of addresses used, ex: 192.168.1.0 | 256. So I need to take just that information there and explode it out to give me, the first IP, last IP, reverse mask, CIDR, start decimal, and end decimal. I can then take this output and do other things with it.

Again, any input is appreciated!

Is This A Good Question/Topic? 0
  • +

Replies To: IP Range to Proper Subnetting - Not quite there

#2 chickensevil  Icon User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 9
  • Joined: 28-July 12

Re: IP Range to Proper Subnetting - Not quite there

Posted 29 July 2012 - 04:03 AM

Well, I think I stumbled upon the answer in a rather easy fix. I think putting the problem out there in this fashion at least really helped me grasp the solution. Based on the testing I have thrown at this it seems to perform quite well, so here is the fix:

    if h <= 256:
        #Can only fill 4th octet
        b = h - CalcFourth(h)
    elif h <= 65536:
        #Possibly 3rd octet
        if h % 256 == 0:
            #definately 3rd octet
            b = h - CalcThird(h)
        else:
            #need to fill 4th octet first
            b = h - CalcFourth(h)
    else:
        #Possibly 2nd octect
        if h % 65536 == 0:
            #definately 2nd octet
            b = h - CalcSecond(h)
        else:
            #need to fill at least 3rd octect first
            if (h % 65536) % 256 == 0:
                #definately 3rd octet
                b = h - CalcThird(h)
            else:
                #need to fill 4th octet first
                b = h - CalcFourth(h)


This block was changed to drop the modification of the number of hosts before pushing it to the relavent function. Basically 352 % 256 % 64 = 0 and so does 352 % 64 = 0. The genius here is doing this proof is the same as saying 2 + 2 + 2 = 6 and 2 + 4 = 6. so puting it into programming terms x % y % z == x % z. This is only true if both y and z are 2^n where n is any number and y and z less than or equal to x.

The only other change was in the nested functions at the below locations, I changed the if statement to greater than or equal to 256 since it was now possible to pass a number into the functions that exceeded that value.

if ip[3] % 256 == 0:
    #ip is 0 since 0/x = 0 special condition
    if v >= 256:
        mh = 256



Anyway, I hope this was clear enough, and is helpful to anyone else looking for this type of problem. If I can provide further details or clarification on anything let me know. I have placed the entire modified function below just so anyone looking will not miss a small change.

def GetHostRemainder(decIP, h):
    #input  int decIP is the decimal IP of the first address in a range
    #       int v is the number of hosts(IPs) in a provided range
    #output b is the remaining number of hosts minus a proper subnet
    #get the regular notation of the IP address into a list
    ip = [decIP/256/65536, (decIP/65536)%256,(decIP/256)%256, decIP%256]
    def CalcFourth(v):
        b = 0
        if ip[3] % 2 == 0:
            if ip[3] % 4 == 0:
                if ip[3] % 8 == 0:
                    if ip[3] % 16 == 0:
                        if ip[3] % 32 == 0:
                            if ip[3] % 64 == 0:
                                if ip[3] % 128 == 0:
                                    if ip[3] % 256 == 0:
                                        #ip is 0 since 0/x = 0 special condition
                                        if v >= 256:
                                            mh = 256
                                        elif v >= 128:
                                            mh = 128
                                        elif v >= 64:
                                            mh = 64
                                        elif v >= 32:
                                            mh = 32
                                        elif v >= 16:
                                            mh = 16
                                        elif v >= 8:
                                            mh = 8
                                        elif v >= 4:
                                            mh = 4
                                        elif v >= 2:
                                            mh = 2
                                        else:
                                            mh = v
                                    else:
                                        #ip is 128
                                        if v >= 128:
                                            mh = 128
                                        elif v >= 64:
                                            mh = 64
                                        elif v >= 32:
                                            mh = 32
                                        elif v >= 16:
                                            mh = 16
                                        elif v >= 8:
                                            mh = 8
                                        elif v >= 4:
                                            mh = 4
                                        elif v >= 2:
                                            mh = 2
                                        else:
                                            mh = v
                                else:
                                    #ip is multiple of 64
                                    if v >= 64:
                                        mh = 64
                                    elif v >= 32:
                                        mh = 32
                                    elif v >= 16:
                                        mh = 16
                                    elif v >= 8:
                                        mh = 8
                                    elif v >= 4:
                                        mh = 4
                                    elif v >= 2:
                                        mh = 2
                                    else:
                                        mh = v
                            else:
                                #ip is multiple of 32
                                if v >= 32:
                                    mh = 32
                                elif v >= 16:
                                    mh = 16
                                elif v >= 8:
                                    mh = 8
                                elif v >= 4:
                                    mh = 4
                                elif v >= 2:
                                    mh = 2
                                else:
                                    mh = v
                        else:
                            #ip is multiple of 16
                            if v >= 16:
                                mh = 16
                            elif v >= 8:
                                mh = 8
                            elif v >= 4:
                                mh = 4
                            elif v >= 2:
                                mh = 2
                            else:
                                mh = v
                    else:
                        #ip is multiple of 8
                        if v >= 8:
                            mh = 8
                        elif v >= 4:
                            mh = 4
                        elif v >= 2:
                            mh = 2
                        else:
                            mh = v
                else:
                    #ip is multiple of 4
                    if v >= 4:
                        mh = 4
                    elif v >= 2:
                        mh = 2
                    else:
                        mh = v
            else:
                #ip is multiple of 2
                if v >= 2:
                    mh = 2
                else:
                    mh = v
        else:
            #ip = odd number
            mh = 1
        b = mh
        return b
    def CalcThird(v):
        b = 0
        if ip[2] % 2 == 0:
            if ip[2] % 4 == 0:
                if ip[2] % 8 == 0:
                    if ip[2] % 16 == 0:
                        if ip[2] % 32 == 0:
                            if ip[2] % 64 == 0:
                                if ip[2] % 128 == 0:
                                    if ip[2] % 256 == 0:
                                        #ip is 0 since 0/x = 0 special condition
                                        v /= 256
                                        if v >= 256:
                                            mh = 256
                                        elif v >= 128:
                                            mh = 128
                                        elif v >= 64:
                                            mh = 64
                                        elif v >= 32:
                                            mh = 32
                                        elif v >= 16:
                                            mh = 16
                                        elif v >= 8:
                                            mh = 8
                                        elif v >= 4:
                                            mh = 4
                                        elif v >= 2:
                                            mh = 2
                                        else:
                                            mh = v
                                    else:
                                        #ip is 128
                                        v /= 256
                                        if v >= 128:
                                            mh = 128
                                        elif v >= 64:
                                            mh = 64
                                        elif v >= 32:
                                            mh = 32
                                        elif v >= 16:
                                            mh = 16
                                        elif v >= 8:
                                            mh = 8
                                        elif v >= 4:
                                            mh = 4
                                        elif v >= 2:
                                            mh = 2
                                        else:
                                            mh = v
                                else:
                                    #ip is multiple of 64
                                    v /= 256
                                    if v >= 64:
                                        mh = 64
                                    elif v >= 32:
                                        mh = 32
                                    elif v >= 16:
                                        mh = 16
                                    elif v >= 8:
                                        mh = 8
                                    elif v >= 4:
                                        mh = 4
                                    elif v >= 2:
                                        mh = 2
                                    else:
                                        mh = v
                            else:
                                #ip is multiple of 32
                                v /= 256
                                if v >= 32:
                                    mh = 32
                                elif v >= 16:
                                    mh = 16
                                elif v >= 8:
                                    mh = 8
                                elif v >= 4:
                                    mh = 4
                                elif v >= 2:
                                    mh = 2
                                else:
                                    mh = v
                        else:
                            #ip is multiple of 16
                            v /= 256
                            if v >= 16:
                                mh = 16
                            elif v >= 8:
                                mh = 8
                            elif v >= 4:
                                mh = 4
                            elif v >= 2:
                                mh = 2
                            else:
                                mh = v
                    else:
                        #ip is multiple of 8
                        v /= 256
                        if v >= 8:
                            mh = 8
                        elif v >= 4:
                            mh = 4
                        elif v >= 2:
                            mh = 2
                        else:
                            mh = v
                else:
                    #ip is multiple of 4
                    v /= 256
                    if v >= 4:
                        mh = 4
                    elif v >= 2:
                        mh = 2
                    else:
                        mh = v
            else:
                #ip is multiple of 2
                v /= 256
                if v >= 2:
                    mh = 2
                else:
                    mh = v
        else:
            #ip = odd number
            mh = 1
        b = mh * 256
        return b
    def CalcSecond(v):
        b = 0
        if ip[1] % 2 == 0:
            if ip[1] % 4 == 0:
                if ip[1] % 8 == 0:
                    if ip[1] % 16 == 0:
                        if ip[1] % 32 == 0:
                            if ip[1] % 64 == 0:
                                if ip[1] % 128 == 0:
                                    if ip[1] % 256 == 0:
                                        #ip is 0 since 0/x = 0 special condition
                                        v /= 65536
                                        if v >= 256:
                                            mh = 256
                                        elif v >= 128:
                                            mh = 128
                                        elif v >= 64:
                                            mh = 64
                                        elif v >= 32:
                                            mh = 32
                                        elif v >= 16:
                                            mh = 16
                                        elif v >= 8:
                                            mh = 8
                                        elif v >= 4:
                                            mh = 4
                                        elif v >= 2:
                                            mh = 2
                                        else:
                                            mh = v
                                    else:
                                        #ip is 128
                                        v /= 65536
                                        if v >= 128:
                                            mh = 128
                                        elif v >= 64:
                                            mh = 64
                                        elif v >= 32:
                                            mh = 32
                                        elif v >= 16:
                                            mh = 16
                                        elif v >= 8:
                                            mh = 8
                                        elif v >= 4:
                                            mh = 4
                                        elif v >= 2:
                                            mh = 2
                                        else:
                                            mh = v
                                else:
                                    #ip is multiple of 64
                                    v /= 65536
                                    if v >= 64:
                                        mh = 64
                                    elif v >= 32:
                                        mh = 32
                                    elif v >= 16:
                                        mh = 16
                                    elif v >= 8:
                                        mh = 8
                                    elif v >= 4:
                                        mh = 4
                                    elif v >= 2:
                                        mh = 2
                                    else:
                                        mh = v
                            else:
                                #ip is multiple of 32
                                v /= 65536
                                if v >= 32:
                                    mh = 32
                                elif v >= 16:
                                    mh = 16
                                elif v >= 8:
                                    mh = 8
                                elif v >= 4:
                                    mh = 4
                                elif v >= 2:
                                    mh = 2
                                else:
                                    mh = v
                        else:
                            #ip is multiple of 16
                            v /= 65536
                            if v >= 16:
                                mh = 16
                            elif v >= 8:
                                mh = 8
                            elif v >= 4:
                                mh = 4
                            elif v >= 2:
                                mh = 2
                            else:
                                mh = v
                    else:
                        #ip is multiple of 8
                        v /= 65536
                        if v >= 8:
                            mh = 8
                        elif v >= 4:
                            mh = 4
                        elif v >= 2:
                            mh = 2
                        else:
                            mh = v
                else:
                    #ip is multiple of 4
                    v /= 65536
                    if v >= 4:
                        mh = 4
                    elif v >= 2:
                        mh = 2
                    else:
                        mh = v
            else:
                #ip is multiple of 2
                v /= 65536
                if v >= 2:
                    mh = 2
                else:
                    mh = v
        else:
            #ip = odd number
            mh = 1
        b = mh * 65536
        return b
    if h <= 256:
        #Can only fill 4th octet
        b = h - CalcFourth(h)
    elif h <= 65536:
        #Possibly 3rd octet
        if h % 256 == 0:
            #definately 3rd octet
            b = h - CalcThird(h)
        else:
            #need to fill 4th octet first
            b = h - CalcFourth(h)
    else:
        #Possibly 2nd octect
        if h % 65536 == 0:
            #definately 2nd octet
            b = h - CalcSecond(h)
        else:
            #need to fill at least 3rd octect first
            if (h % 65536) % 256 == 0:
                #definately 3rd octet
                b = h - CalcThird(h)
            else:
                #need to fill 4th octet first
                b = h - CalcFourth(h)
    return b


Was This Post Helpful? 2
  • +
  • -

#3 chickensevil  Icon User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 9
  • Joined: 28-July 12

Re: IP Range to Proper Subnetting - Not quite there

Posted 29 July 2012 - 04:12 AM

Final note, this all runs surprisingly faster than expected. The overall code which pulls 5 files containing IP address lists, parses through them and outputs to a file in about 5 seconds. The output file is a csv which ends up with over 124,000 entries and encompasses the entire *usable* IP space. So even with all the "bloat" of the if/else statements, this code runs really fast.

Again any optimization suggestions are welcome, but I thought I would mention the speed since I was expecting far more lag.
Was This Post Helpful? 1
  • +
  • -

#4 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 6062
  • View blog
  • Posts: 23,513
  • Joined: 23-August 08

Re: IP Range to Proper Subnetting - Not quite there

Posted 29 July 2012 - 09:47 AM

Quote

I think putting the problem out there in this fashion at least really helped me grasp the solution


It often does (see rubber duck debugging). Thanks so much for letting us know your solution!
Was This Post Helpful? 1
  • +
  • -

#5 Nallo  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 163
  • View blog
  • Posts: 255
  • Joined: 19-July 09

Re: IP Range to Proper Subnetting - Not quite there

Posted 30 July 2012 - 09:02 AM

You asked for optimization but never said which optimization you were looking for. Since all those repeated code and the nesting of ifs looks ugly I did a bit of DRYing your code. Shorting your CalcFourth function in several steps. It may make it slower though, but I guess the timehog is in IO Operations anyway. No way to test that from here:

def CalcFourth(v):
    b = 0
    if ip[3] % 2 == 0:
        if ip[3] % 4 == 0:
            if ip[3] % 8 == 0:
                if ip[3] % 16 == 0:
                    if ip[3] % 32 == 0:
                        if ip[3] % 64 == 0:
                            if ip[3] % 128 == 0:
                                if ip[3] % 256 == 0:
                                    #ip is 0 since 0/x = 0 special condition
                                    if v >= 256:
                                        mh = 256
                                    elif v >= 128:
                                        mh = 128
                                    elif v >= 64:
                                        mh = 64
                                    elif v >= 32:
                                        mh = 32
                                    elif v >= 16:
                                        mh = 16
                                    elif v >= 8:
                                        mh = 8
                                    elif v >= 4:
                                        mh = 4
                                    elif v >= 2:
                                        mh = 2
                                    else:
                                        mh = v
                                else:
                                    #ip is 128
                                    if v >= 128:
                                        mh = 128
                                    elif v >= 64:
                                        mh = 64
                                    elif v >= 32:
                                        mh = 32
                                    elif v >= 16:
                                        mh = 16
                                    elif v >= 8:
                                        mh = 8
                                    elif v >= 4:
                                        mh = 4
                                    elif v >= 2:
                                        mh = 2
                                    else:
                                        mh = v
                            else:
                                #ip is multiple of 64
                                if v >= 64:
                                    mh = 64
                                elif v >= 32:
                                    mh = 32
                                elif v >= 16:
                                    mh = 16
                                elif v >= 8:
                                    mh = 8
                                elif v >= 4:
                                    mh = 4
                                elif v >= 2:
                                    mh = 2
                                else:
                                    mh = v
                        else:
                            #ip is multiple of 32
                            if v >= 32:
                                mh = 32
                            elif v >= 16:
                                mh = 16
                            elif v >= 8:
                                mh = 8
                            elif v >= 4:
                                mh = 4
                            elif v >= 2:
                                mh = 2
                            else:
                                mh = v
                    else:
                        #ip is multiple of 16
                        if v >= 16:
                            mh = 16
                        elif v >= 8:
                            mh = 8
                        elif v >= 4:
                            mh = 4
                        elif v >= 2:
                            mh = 2
                        else:
                            mh = v
                else:
                    #ip is multiple of 8
                    if v >= 8:
                        mh = 8
                    elif v >= 4:
                        mh = 4
                    elif v >= 2:
                        mh = 2
                    else:
                        mh = v
            else:
                #ip is multiple of 4
                if v >= 4:
                    mh = 4
                elif v >= 2:
                    mh = 2
                else:
                    mh = v
        else:
            #ip is multiple of 2
            if v >= 2:
                mh = 2
            else:
                mh = v
    else:
        #ip = odd number
        mh = 1
    b = mh
    return b


def power_of_2_less_than_v(v, m2):
    """For v>0 returns the biggest power of 2 that is less or equal to v
    and less or equal to m2. For v=0 returns 0.
    m2 has to be a power of 2.
    >>> power_of_2_less_than_v(0, 128)
    0
    >>> power_of_2_less_than_v(352, 256)
    256
    >>> power_of_2_less_than_v(256, 256)
    256
    >>> power_of_2_less_than_v(129, 64)
    64
    >>> power_of_2_less_than_v(48, 128)
    32
    """
    while m2 >= 2:
        if v >= m2:
            return m2
        else:
            m2 /= 2
    return v
        
#getting rid of some if's and unneeded variables
def CalcFourth_v2(v):
    if ip[3] % 2 == 0:
        if ip[3] % 4 == 0:
            if ip[3] % 8 == 0:
                if ip[3] % 16 == 0:
                    if ip[3] % 32 == 0:
                        if ip[3] % 64 == 0:
                            if ip[3] % 128 == 0:
                                if ip[3] % 256 == 0:
                                    #ip is 0 since 0/x = 0 special condition
                                    return power_of_2_less_than_v(v, 256)
                                else:
                                    #ip is 128
                                    return power_of_2_less_than_v(v, 128)
                            else:
                                #ip is multiple of 64
                                return power_of_2_less_than_v(v, 64)
                        else:
                            #ip is multiple of 32
                            return power_of_2_less_than_v(v, 32)
                    else:
                        #ip is multiple of 16
                        return power_of_2_less_than_v(v, 16)
                else:
                    #ip is multiple of 8
                    return power_of_2_less_than_v(v, 8)
            else:
                #ip is multiple of 4
                return power_of_2_less_than_v(v, 4)
        else:
            #ip is multiple of 2
            return power_of_2_less_than_v(v, 2)
    else:
        #ip = odd number
        return 1


#getting rid of the nesting by testing the strongest condition first
#instead of the weakest
def CalcFourth_v3(v):
    if ip[3] % 256 == 0:
        #ip is 0 since 0/x = 0 special condition
        return power_of_2_less_than_v(v, 256)
    elif ip[3] % 128 == 0:
        #ip is 128
        return power_of_2_less_than_v(v, 128)
    elif ip[3] % 64 == 0:
        #ip is multiple of 64
        return power_of_2_less_than_v(v, 64)
    elif ip[3] % 32 == 0:
        #ip is multiple of 32
        return power_of_2_less_than_v(v, 32)
    elif ip[3] % 16 == 0:
        #ip is multiple of 16
        return power_of_2_less_than_v(v, 16)
    elif ip[3] % 8 == 0:
        #ip is multiple of 8
        return power_of_2_less_than_v(v, 8)
    elif ip[3] % 4 == 0:
        #ip is multiple of 4
        return power_of_2_less_than_v(v, 4)
    elif ip[3] % 2 == 0:
        #ip is multiple of 2
        return power_of_2_less_than_v(v, 2)
    else:
        #ip = odd number
        return 1


#using a loop to spare some lines of code
def CalcFourth_v4(v):
    for x in [256, 128, 64, 32, 16, 8, 4, 2]:
        if ip[3] % x == 0:
            #ip is multiple of x
            #special case ip[3] == 0. catched by x == 256, as 0%256 == 0
            return power_of_2_less_than_v(v, x)
    #ip is odd number
    return 1


#giving CalcFourth the same form as the other Calcs
#so you need only one function instead of 3
def CalcFourth_v5(v):
    ip_pos = 3
    for x in [256, 128, 64, 32, 16, 8, 4, 2]:
        if ip[ip_pos] % x == 0:
            #ip is multiple of x
            #special case ip[3] == 0. catched by x == 256, as 0%256 == 0
            v /= 256 ** (3 - ip_pos)
            return power_of_2_less_than_v(v, x)
    #ip is odd number
    return 1


#now we can write the three calc functions as one
#CalcFourth is now Calc(v, 4)
#CalcThird is Calc(v, 3) ...
def Calc(v, octet):
    octet -= 1
    for x in [256, 128, 64, 32, 16, 8, 4, 2]:
        if ip[octet] % x == 0:
            #ip is multiple of x, but not of powers of 2 greater than x
            #special case ip[3] == 0. catched by x == 256, as 0%256 == 0
            v /= 256 ** (3 - octet)
            return power_of_2_less_than_v(v, x)
    #ip is odd number
    return 1



Making your whole get_host_remainder function into:

def GetHostRemainder(decIP, h):
    #input  int decIP is the decimal IP of the first address in a range
    #       int v is the number of hosts(IPs) in a provided range
    #output of is the remaining number of hosts minus a proper subnet
    #get the regular notation of the IP address into a list
    ip = [decIP/256/65536, (decIP/65536)%256,(decIP/256)%256, decIP%256]
    def power_of_2_less_than_v(v, m2):
        """For v>0 returns the biggest power of 2 that is less or equal to v
        that is at most m2. For v=0 returns 0.
        m2 has to be a power of 2.
        >>> power_of_2_less_than_v(0, 128)
        0
        >>> power_of_2_less_than_v(352, 256)
        256
        >>> power_of_2_less_than_v(256, 256)
        256
        >>> power_of_2_less_than_v(129, 64)
        64
        >>> power_of_2_less_than_v(48, 128)
        32
        """
        while m2 >= 2:
            if v >= m2:
                return m2
            else:
                m2 /= 2
        return v

    def Calc(v, octet):
        octet -= 1
        for x in [256, 128, 64, 32, 16, 8, 4, 2]:
            if ip[octet] % x == 0:
                #ip is multiple of x
                #special case ip[3] == 0. catched by x == 256, as 0%256 == 0
                v /= 256 ** (3 - octet)
                return power_of_2_less_than_v(v, x)
        #ip is odd number
        return 1

    if h <= 256:
        #Can only fill 4th octet
        b = h - Calc(h, 4)
    elif h <= 65536:
        #Possibly 3rd octet
        if h % 256 == 0:
            #definately 3rd octet
            b = h - Calc(h, 3)
        else:
            #need to fill 4th octet first
            b = h - Calc(h, 4)
    else:
        #Possibly 2nd octect
        if h % 65536 == 0:
            #definately 2nd octet
            b = h - Calc(h, 2)
        else:
            #need to fill at least 3rd octect first
            if (h % 65536) % 256 == 0:
                #definately 3rd octet
                b = h - Calc(h, 3)
            else:
                #need to fill 4th octet first
                b = h - Calc(h, 4)
    return b



If you are striving for speed (and IO is not the most timeconsuming part) you may try to replace some calculations with lookuptables (dictionaries and sets)
Was This Post Helpful? 1
  • +
  • -

#6 chickensevil  Icon User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 9
  • Joined: 28-July 12

Re: IP Range to Proper Subnetting - Not quite there

Posted 09 August 2012 - 10:17 PM

Sorry I didnt get back to this sooner, My email account must have spammed the message or something.

Thank you for the response, that shortens it up a ton, and I dont know that it would be noticeably slower at this point. IO is the worst, which is why my overall program has very little.

There was one issue with the code, that I noticed, you forgot to re-multiply up the value after you reduce it down. your power of 2 function works just fine if you are on the 4th octet, but you have to remember to multiply back up on the others. so all I had to change was on the return value of Calc() to this:
return 256 ** (3 - octet) * power_of_2_less_than_v(v, x)

Otherwise, its much smaller than before so thank you! Dunno about faster, but definately easier for me to scroll through and read haha!
Was This Post Helpful? 0
  • +
  • -

#7 chickensevil  Icon User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 9
  • Joined: 28-July 12

Re: IP Range to Proper Subnetting - Not quite there

Posted 09 August 2012 - 10:37 PM

Ok, So after throwing the entire IP range at this thing I have found that it still doesnt quite subnet correctly... (quite literally, if you wanna know the source materials go to ftp.arin.net/pub/stats, and you can pull down all the ranges for each RIR. Would love to get direct whois pulls... but they dont like that too much...)

So I have changed one segment of code yet again, and thats the primary if/else condition. Instead of doing modulous division I check each IP starting from the back moving forward for a non 0 value. I sat and thought a long time about it, and could not for the life of me think of a situation that wouldnt result in this producing accurate results... When I get to pushing it all through the ringer I will post back if I find any other issues. So here is the modified snippet:

    if h <= 256:
        #Can only fill 4th octet
        b = h - Calc(h, 4)
    elif h <= 65536:
        #Possibly 3rd octet
        if ip[3] == 0:
            #definately 3rd octet
            b = h - Calc(h, 3)
        else:
            #need to fill 4th octet first
            b = h - Calc(h, 4)
    else:
        #Possibly 2nd octect
        if ip[3] == 0:
            if ip[2] == 0:
                #definately 2nd octet
                b = h - Calc(h, 2)
            else:
                #need to fill 3rd octet first
                b = h - Calc(h, 3)
        else:
            #need to fill 4th octet first
            b = h - Calc(h, 4)


This is using Nallo's modifications for the new Calc() function but otherwise, its straight forward. Here is a stand along snippet if you would like to see the whole thing churn out a pretty wide range correctly:

import os
import sys

def ConvertMaskToCIDR(mask):
    #input IP as string with / CIDR notation (limit 8 to 32)
    #output reverse subnet mask or empty string if 32
    cidr = ''
    if mask == "0.255.255.255":
        cidr = "8"
    elif mask == "0.127.255.255":
        cidr = "9"
    elif mask == "0.63.255.255":
        cidr = "10"
    elif mask == "0.31.255.255":
        cidr = "11"
    elif mask == "0.15.255.255":
        cidr = "12"
    elif mask == "0.7.255.255":
        cidr = "13"
    elif mask == "0.3.255.255":
        cidr = "14"
    elif mask == "0.1.255.255":
        cidr = "15"
    elif mask == "0.0.255.255":
        cidr = "16"
    elif mask == "0.0.127.255":
        cidr = "17"
    elif mask == "0.0.63.255":
        cidr = "18"
    elif mask == "0.0.31.255":
        cidr = "19"
    elif mask == "0.0.15.255":
        cidr = "20"
    elif mask == "0.0.7.255":
        cidr = "21"
    elif mask == "0.0.3.255":
        cidr = "22"
    elif mask == "0.0.1.255":
        cidr = "23"
    elif mask == "0.0.0.255":
        cidr = "24"
    elif mask == "0.0.0.127":
        cidr = "25"
    elif mask == "0.0.0.63":
        cidr = "26"
    elif mask == "0.0.0.31":
        cidr = "27"
    elif mask == "0.0.0.15":
        cidr = "28"
    elif mask == "0.0.0.7":
        cidr = "29"
    elif mask == "0.0.0.3":
        cidr = "30"
    elif mask == "0.0.0.1":
        cidr = "31"
    else:
        cidr = '0.0.0.0'
    return cidr


def GetHostRemainder(decIP, h):
    #input  int decIP is the decimal IP of the first address in a range
    #       int v is the number of hosts(IPs) in a provided range
    #output of is the remaining number of hosts minus a proper subnet
    #get the regular notation of the IP address into a list
    ip = [decIP/256/65536, (decIP/65536)%256,(decIP/256)%256, decIP%256]
    def power_of_2_less_than_v(v, m2):
        """For v>0 returns the biggest power of 2 that is less or equal to v
        that is at most m2. For v=0 returns 0.
        m2 has to be a power of 2.
        >>> power_of_2_less_than_v(0, 128)
        0
        >>> power_of_2_less_than_v(352, 256)
        256
        >>> power_of_2_less_than_v(256, 256)
        256
        >>> power_of_2_less_than_v(129, 64)
        64
        >>> power_of_2_less_than_v(48, 128)
        32
        """
        while m2 >= 2:
            if v >= m2:
                return m2
            else:
                m2 /= 2
        return v
    def Calc(v, octet):
        octet -= 1
        for x in [256, 128, 64, 32, 16, 8, 4, 2]:
            if ip[octet] % x == 0:
                #ip is multiple of x
                #special case ip[3] == 0. catched by x == 256, as 0%256 == 0
                v /= 256 ** (3 - octet)
                return 256 ** (3 - octet) * power_of_2_less_than_v(v, x)
        #ip is odd number
        return 1
    if h <= 256:
        #Can only fill 4th octet
        b = h - Calc(h, 4)
    elif h <= 65536:
        #Possibly 3rd octet
        if ip[3] == 0:
            #definately 3rd octet
            b = h - Calc(h, 3)
        else:
            #need to fill 4th octet first
            b = h - Calc(h, 4)
    else:
        #Possibly 2nd octect
        if ip[3] == 0:
            if ip[2] == 0:
                #definately 2nd octet
                b = h - Calc(h, 2)
            else:
                #need to fill 3rd octet first
                b = h - Calc(h, 3)
        else:
            #need to fill 4th octet first
            b = h - Calc(h, 4)
    return b

def ConvertIPToDecimal(ip):
    #input IP as string
    #output Decimal IP as string
    #
    #Formula:
    #16777216*w + 65536*x + 256*y + z
    ip = ip.split('.')
    decIP = str((16777216 * int(ip[0])) +
                  (65536 * int(ip[1])) +
                  (256 * int(ip[2])) +
                  (int(ip[3])))
    return decIP

def ConvertDecimalToIP(dec):
    #input dec as sting
    #output IP as string
    #
    #Formula (i/256/65536).((i/65536)%256).((i/256)%256).(i%256)
    ip = str(int(dec)//256//65536) + '.' \
       + str((int(dec)//65536)%256) + '.' \
       + str((int(dec)//256)%256) + '.' \
       + str(int(dec)%256)
    return ip

v = 1932288
sIP = '10.158.0.0'
sDec = ''
b = 0
eDec = ''
mask = ''
r = ''
eIP = ''
row = []
route = []

while v > 0:
    sDec = ConvertIPToDecimal(sIP)
    #need to accomodate non-CIDR networks
    b = GetHostRemainder(int(sDec), v)
    #gets the nearest whole network
    v -= b
    #calculate sDec and eDec
    eDec = str(int(sDec) + int(v) - 1)
    #get mask and route
    if v != '1':
        #anything but a /32 should go here
        mask = ConvertDecimalToIP(str(int(v) - 1))
        r = sIP + '/' + ConvertMaskToCIDR(mask)
    else:
        #/32 here, has special entry in ACL
        mask = ''
        r = sIP
    #calculate eIP
    eIP = ConvertDecimalToIP(eDec)
    #save data to row[] and append to route[]
    row = [sIP, eIP, mask, r, sDec, eDec,]
    route.append(row)
    row = []
    #get next v if b has anything left over
    if b == 0:
        #no left overs, all in proper subnet
        v = 0
    else:
        #hosts remaining, move start IP past range covered
        sIP = ConvertDecimalToIP(str(int(sDec) + v))
        #move b into v and run again.
        v = b

for row in route:
    print row


This is actually straight from the real thing, I just anonomised the range. It should output 10 routes, each of varying subnets. The reason I hit such a large number of hosts is from the other part of the code which actually takes similar ranges and consolidates them. This whole thing, is because I was tired of hitting the internet to do things and needed to code it myself. Now anyone can hopefully find this in google and have a working example, instead of being at the mercy of a web application and people who wont push their source code out there.
Was This Post Helpful? 0
  • +
  • -

#8 chickensevil  Icon User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 9
  • Joined: 28-July 12

Re: IP Range to Proper Subnetting - Not quite there

Posted 09 August 2012 - 11:35 PM

Sorry Nallo, one more little goof that I didnt catch until throwing the entire book at this, same issue from the first correction, I just missed the "return 1" part. So modifying that one little piece and I seem to be logic error free... for now...

So here is the now complete Calc() function:
    def Calc(v, octet):
        ##input   v     - total number of hosts unsubnetted
        ##        octet - which octet the subnet resides
        ##output  number of hosts in full decimal notation
        ##by dividing the ip of the specified octet by power of 2, the maximum
        ##size of a legal subnet can be obtained. Once this value is obtained
        ##power_of_2_less_than_v() is called to determine how many of the
        ##provided hosts actually fit.
        octet -= 1
        for x in [256, 128, 64, 32, 16, 8, 4, 2]:
            if ip[octet] % x == 0:
                #ip is multiple of x
                #special case ip[3] == 0. catched by x == 256, as 0%256 == 0
                v /= 256 ** (3 - octet)
                #multiply back up the hosts based on octet (3-3 = 0, 256^0 = 1)
                return 256 ** (3 - octet) * power_of_2_less_than_v(v, x)
        #ip is odd number
        return 256 ** (3 - octet)


So instead of returning 1 on an odd number just return the correct power of 256 based on octet. So 256 ** 0 = 1, 256 ** 1 = 256, and 256 ** 2 = 65536.

Interrestingly, since I do not want anything exceeding a /8 (single class A) it would appear that based on not accounting for anything over a /8 will just subnet them into multiple class As. Which is fine by me, since realistically there should be no reason to ever ACL more than a single class A at a time.
Was This Post Helpful? 0
  • +
  • -

#9 chickensevil  Icon User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 9
  • Joined: 28-July 12

Re: IP Range to Proper Subnetting - Not quite there

Posted 10 August 2012 - 12:37 AM

It should be in a full workable fashion now, I made it was stand alone from anything else I was doing, and should function as is almost. The only thing need be changed is the output location. This is on line 348 (almost the very bottom of the file). Just name the location whatever and enjoy.

Here are the added pieces to the already listed segments:

def RouteDump(sourceDB):
    # Input a source database file which is already opened and at the beginning
    #   of the file. Will have layout of following format
    #       registry | CC | type | start | value | date | status
    #           type - {asn,ipv4,ipv6}
    #           start - first IP or first ASN digit
    #           value - if IP will be number of hosts (ie 256 = /24) but does
    #                   not have to be a CIDR range (ugh!!!!)
    #
    # Output a list containing the following csv-style formatting
    #    Start IP, Stop IP, Mask, Route (CIDR), Country, Source,
    #              Start Dec, Stop Dec
    write = sys.stdout.write
    write('Get Routes from DB') #needed a little output prints same line
    route   = []       #This will be the output container
    row     = []       #Each row is loaded into route container
    seg     = []       #Segments for each line split
    sIP     = ''       #Start IP
    eIP     = ''       #End IP
    mask    = ''       #Reverse Subnet Mask
    r       = ''       #Route stored here goes in row[]
    c       = ''       #Country stored here goes in row[]
    s       = ''       #Source stored here goes in row[]
    sDec    = ''       #Start Decimal IP
    eDec    = ''       #End Decimal IP
    v       = ''       #Value Field
    i       = 687865856#control variable for pretty printing
    j       = 5        #control for total number of IP entries (start on non 0
                       #purpose)
    for line in sourceDB.readlines():
        if not line.startswith('#') and not line.startswith('\n'):
            if line.split('|')[2] == 'ipv4' and line.split('|')[1] != '*': #Route found
                j -= 1 #when j hits 0 we are on the last entry
                seg = line.split('|')  #0-s|1-c|3-sIP|4-v
                s = seg[0]
                if c == seg[1] and int(ConvertIPToDecimal(seg[3])) - \
                                      int(ConvertIPToDecimal(sIP)) == v:
                    #next country same as last and compatible IP
                    v += int(seg[4])
                elif c != '':
                    b = 0
                    #dump the old information since countries no longer match
                    #and update the output
                    while v > 0:
                        sDec = ConvertIPToDecimal(sIP)
                        #need to accomodate non-CIDR networks
                        b = GetHostRemainder(int(sDec), v)
                        #gets the nearest whole network
                        v -= b
                        #calculate sDec and eDec
                        eDec = str(int(sDec) + int(v) - 1)
                        #get mask and route
                        if v != '1':
                            #anything but a /32 should go here
                            mask = ConvertDecimalToIP(str(int(v) - 1))
                            r = sIP + '/' + ConvertMaskToCIDR(mask)
                        else:
                            #/32 here, has special entry in ACL
                            mask = ''
                            r = sIP
                        #calculate eIP
                        eIP = ConvertDecimalToIP(eDec)
                        #save data to row[] and append to route[]
                        row = [sIP, eIP, mask, r, c, s, sDec, eDec,]
                        route.append(row)
                        row = []
                        #get next v if b has anything left over
                        if b == 0:
                            #no left overs, all in proper subnet
                            v = 0
                        else:
                            #hosts remaining, move start IP past range covered
                            sIP = ConvertDecimalToIP(str(int(sDec) + v))
                            #move b into v and run again.
                            v = b
                    if int(eDec) >= i:
                        i += 738017279   #This magic number should always make 5 '.'
                        write('.')       #needed a little output prints same line
                    #update varibles with the new information and loop again.
                    c = seg[1]
                    sIP = seg[3]
                    v = int(seg[4])
                else: #handle for the first line of the file
                    c = seg[1]
                    sIP = seg[3]
                    v = int(seg[4])
            elif line.split('|')[2] == 'ipv4' and line.split('|')[1] == '*':
                #there will only be one row toward the beginning with ipv4 and *
                #this row is a summary and seg[4] will specify number of entries
                seg = line.split('|')
                j = int(seg[4])
            elif j <= 0:
                #this is why j must start on a non 0, since this would trigger
                #falsely on any lines before j gets initialized. Once this runs
                #once change j back above 0 so it will not run again and the
                #script will push to end of file.
                j = 5
                b = 0
                #dump all data left into output.
                while v > 0:
                    sDec = ConvertIPToDecimal(sIP)
                    #need to accomodate non-CIDR networks
                    b = GetHostRemainder(int(sDec), v)
                    #gets the nearest whole network
                    v -= b
                    #calculate sDec and eDec
                    eDec = str(int(sDec) + int(v) - 1)
                    #get mask and route
                    if v != '1':
                        #anything but a /32 should go here
                        mask = ConvertDecimalToIP(str(int(v) - 1))
                        r = sIP + '/' + ConvertMaskToCIDR(mask)
                    else:
                        #/32 here, has special entry in ACL
                        mask = ''
                        r = sIP
                    #calculate eIP
                    eIP = ConvertDecimalToIP(eDec)
                    #save data to row[] and append to route[]
                    row = [sIP, eIP, mask, r, c, s, sDec, eDec,]
                    route.append(row)
                    row = []
                    #get next v if b has anything left over
                    if b == 0:
                        #no left overs, all in proper subnet
                        v = 0
                    else:
                        #hosts remaining, move start IP past range covered
                        sIP = ConvertDecimalToIP(str(int(sDec) + v))
                        #move b into v and run again.
                        v = b
                if int(eDec) >= i:
                    i += 738017279   #This magic number should always make 4 '.'
                    write('.')       #needed a little output prints same line
    write('\n') #end sameline printing
    return route

#FTP Pull
allRoute = []
print 'Open FTP location, login, and navigate to correct folder'
ftp = ftplib.FTP('ftp.arin.net')
ftp.login()
ftp.cwd('pub/stats')
#used for getting the different files
rir = ['afrinic', 'apnic', 'arin', 'lacnic', 'ripencc']
#memory stored "file-like" object
for r in rir:
    print 'downloading ' + r
    f = StringIO.StringIO()
    ftp.cwd(r)
    ftp.retrbinary('RETR delegated-' + r + '-latest', f.write)
    #need to seek to beginning since we are sitting at the end
    f.seek(0)
    route = RouteDump(f)
    allRoute += route
    #close file (destroys the memory holding file - gone for good at this point)
    f.close()
    ftp.cwd('..')
ftp.close()

#change this to wherever you want the file saved
outfile = open('C:\\Users\\username\\Desktop\\routes.csv', 'wb')
writer = csv.writer(outfile)
writer.writerows(allRoute)
outfile.close()


Be aware this pulls the files directly from ARIN via FTP connection. I dont recommend hitting them repeatedly as they may block you. If you really want to play around with the code, manually download each file and then just reference them in a loop like this:

#Local Pull (For testing)
filedir = 'C:\\Users\\username\\Desktop\\WhoIs DB Files\\'
files = os.listdir(filedir)
allRoute = []
for f in files:
    if f.endswith('-latest') and f.startswith('delegated-'):
        g = open(filedir + '\\' + f, 'rb')
        route = RouteDump(g)
        allRoute += route
        g.close()


Nallo, or anyone else, I am open to making the RouteDump() function look/feel better I hope this wasnt too confusing what I did. Basically each RIR only has to list the start IP and the number of hosts... they dont have to be subnetted properly, nor consolidated in any fashion... some RIRs were better than others, but this code should account for any forseen problems. As it goes through the file, it kinda does a buffer of the previous line. I know how many rows in the file are IPv4 since the entry at the top tells me. This is the reason behind the J control variable. Unfortunately I have a segment of redunancy when J reaches 0 I am running the GetHostRemainder() section one last time. Since it was a single extra call, I didnt think it would really make things better to call a function.

I chose to only consolidate based on country code, if however you wanted to change this so you could consolidate on something else, it should be pretty easy to do. If say you wanted to make something like this: "https://www.countryipblocks.net/ip_aggregation_beta.php" it should be fairly easy to accomplish as the hardest parts are already done.

I tried to simplify the thought process below, so if this is to be modified anyone can rearrange the information.
if line.split('|')[2] == 'ipv4' and line.split('|')[1] != '*': #Route found
    j -= 1 #when j hits 0 we are on the last entry
    seg = line.split('|')  #0-s|1-c|3-sIP|4-v
    if control == true and ip2 - ip1 == v:
        #whatever you a consolidating on and check to make sure 
        #the ranges are compatible (back to back)
        v += int(seg[4])
    elif control == false:
        #dump the old information since control is no longer true
        #and update the output
            while v > 0:
                #subnet portion here
        #update varibles with the new information and loop again.
        c = seg[1]
        sIP = seg[3]
        v = int(seg[4])
    else: 
        #handle for the first line of the file this has to be a 
        #special condition to create a starting point to work from
        c = seg[1]
        sIP = seg[3]
        v = int(seg[4])
elif line.split('|')[2] == 'ipv4' and line.split('|')[1] == '*':
    #there will only be one row toward the beginning with ipv4 and *
    #this row is a summary and seg[4] will specify number of entries
    seg = line.split('|')
    j = int(seg[4])
elif j <= 0:
    #this is why j must start on a non 0, since this would trigger
    #falsely on any lines before j gets initialized. Once this runs
    #once change j back above 0 so it will not run again and the
    #script will push to end of file.
    #dump the old information since control is no longer true
    #and update the output
        while v > 0:
            #subnet portion here



And... I think thats about it. Full thing is attached, I hope this helps some other poor lost soul out there in need of their own IP address consolidation and subnetter (is that actually a word... oh well, is now).
Attached File  RIRStatConsolidation.txt (14.08K)
Number of downloads: 50
Was This Post Helpful? 0
  • +
  • -

#10 blank_program  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 11
  • View blog
  • Posts: 282
  • Joined: 22-July 09

Re: IP Range to Proper Subnetting - Not quite there

Posted 10 August 2012 - 01:13 PM

Here is a class I did for a previous project where you were given a random netmask and IP and had to determine the network it was part of. I wanted to just keep it to myself but by nature Python should be shared so here you go. May need tweaking for your needs and some of it may not be completely clear and can be done better, but I did it when I was first trying to learn Python.

'''
filename:  netinfo.py
version:   1.0.3
rev date:  Jan 30, 2012
desc:      network address calculation module
reqs:      python 3.2
'''

from math import pow as mp
from random import choice
from random import randint as ri

#class containing all information about a given network
class netdata:
    def __init__(self):
        self.addr = ''
        self.netmask = ''
        self.netaddr = ''
        self.fhost = ''
        self.lhost = ''
        self.bcast = ''

        self.hostcount = 0
        self.netcount = 0

        self.netbits = 0


    #determine the number of available hosts and network for specified self.address
    def hncount(self):
        self.hostcount
        self.netcount

        #count number of hosts by counting bits remaining after self.netmask
        self.hostcount = mp(2, (32 - self.netbits)) - 2

        #find number of networks by using netbits count and class masks
        if self.netbits == 8 or self.netbits == 16 or self.netbits == 24:
            self.netcount = 1
        elif 8 < self.netbits < 16:
            self.netcount = mp(2, (16 - self.netbits))
        elif 16 < self.netbits < 24:
            self.netcount = mp(2, (24 - self.netbits))
        elif 24 < self.netbits:
            self.netcount = mp(2, (self.netbits - 24))


    #using given ip find self.netmask
    def gennmask(self, addr):
        #self.netmask octets
        noctets = []

        #split given info into relevant parts
        octets = addr.split('/')[0].split('.')

        #using netbits generate a binary self.netmask as a single string
        self.netmask = ''
        while len(self.netmask) < 32:
            if len(self.netmask) < self.netbits:
                self.netmask = self.netmask + '1'
            else:
                self.netmask = self.netmask + '0'

        #build noctets array by splitting self.netmask binary string
        noctets.append(self.netmask[0:8])
        noctets.append(self.netmask[8:16])
        noctets.append(self.netmask[16:24])
        noctets.append(self.netmask[24:32])

        #find decimal values for binary parts of self.netmask
        sub = ''
        for i in range(4):
            n = noctets[i].count('1')

            if n != 0:
                noctets[i] = int(mp(2, n))
            else:
                noctets[i] = 0

            if noctets[i] == 256:
                noctets[i] = int(noctets[i] - 1)
            elif noctets[i] > 0:
                noctets[i] = int(256 - mp(2, 8 - n))

        #create printable string from decimal self.netmask values
        for i in range(3):
            sub = sub + str(noctets[i]) + '.'
        sub = sub + str(noctets[3])

        self.netmask = sub

        #after setting self.netmask run netself.addrs function to get remaining self.addresses
        self.netaddrs()


    #determine if an ip self.address supplied is valid
    def validip(self, octets):
        if type(octets) == 'string':
            octets = int(octets.split('.'))

        #verify there are exactly 4 sets of digits
        if len(octets) != 4:
            return False
        #verify the first octet is a valid self.address digit
        if octets[0] == 127:
            return False
        #verify no octets are over 255
        else:
            for o in octets:
                if o > 255:
                    return False
            return True


    #generate a random ip self.address and self.netmask
    def ipgen(self):
        #first bit should ignore loopback and apipa addresses
        fbit = list(range(1, 126)) + list(range(128, 168))
        fbit = fbit + list(range(170, 223))
        #remaining bits can be any valid value
        rbit = list(range(1, 255))

        #random self.netmask between 8 and 30 bits
        self.netbits = ri(8, 30)

        #generate a random set of octets using specified ranges
        octets = [choice(fbit), choice(rbit), choice(rbit), choice(rbit)]
        genaddr = ''

        #verify the generated address is valid and if so build address string
        if self.validip(octets):
            for o in range(3):
                genaddr = genaddr + str(octets[o]) + '.'
            genaddr = genaddr + str(octets[3])

            #append netbits to self.address to form CIDR self.address
            self.addr = genaddr

            #count number of hosts and networks for the given mask
            self.hncount()
            self.gennmask(genaddr)

        else:
            print('Invalid address')


    #using netmask find first host, last host, and broadcast addresses
    def netaddrs(self):
        noctets = self.netmask.split('.')

        #network, first host, and last host addresses
        naddr = []
        nfhost = []
        nlhost = []
        nbcast = []

        #loop each octet to determine the network address
        for o in range(len(noctets)):
            #counter determines network intervals
            counter = 256 - int(noctets[o])
            #net used to track octet value
            net = 256
            
            #if netmask octet is 255 copy corresponding address octet
            if int(noctets[o]) == 255:
                naddr.append(self.addr.split('.')[o])
            else:
                if int(noctets[o]) > 0:
                    #while net value is above noctet value decrement by counter
                    while net > int(self.addr.split('.')[o]):
                        net = net - counter
                    naddr.append(net)
                else:
                    naddr.append(0)

        #use octets in network address to determine first host
        for o in range(len(naddr)):
            #copy network octets from network address if they are not 0
            if naddr[o] != 0:
                if o < 3:
                    nfhost.append(naddr[o])
                else:
                    nfhost.append(int(naddr[o]) + 1)
            else:
                if o < 3:
                    nfhost.append(0)
                else:
                    nfhost.append(1)

        #calculate last host address using netmask and first host address
        for o in range(len(naddr)):
            #counter determines network intervals
            counter = 256 - int(self.netmask.split('.')[o])
            #net used to track octet value
            net = 0
            
            if int(self.netmask.split('.')[o]) != 0:
                #copy network octets if netmask octet is 255
                if int(self.netmask.split('.')[o]) == 255:
                    nlhost.append(naddr[o])
                else:
                    #increment network address to the next value
                    while net <= int(naddr[o]):
                        net = net + counter
                    #subtract one to move address to the proper network
                    if self.netbits < 24:
                        nlhost.append(net - 1)
                    else:
                        nlhost.append(net - 2)
            else:
                if o < 3:
                    nlhost.append(255)
                else:
                    nlhost.append(254)

        #use last host address to calculate the broadcast address
        for o in range(len(nlhost)):
            #first three octets match last host address
            if o < 3:
                nbcast.append(nlhost[o])
            #broadcast address is 1 address above last host
            else:
                nbcast.append(int(nlhost[o]) + 1)

        #create address strings
        for o in range(3):
            self.netaddr = self.netaddr + str(naddr[o]) + '.'
            self.fhost = self.fhost + str(nfhost[o]) + '.'
            self.lhost = self.lhost + str(nlhost[o]) + '.'
            self.bcast = self.bcast + str(nbcast[o]) + '.'
        self.netaddr = self.netaddr + str(naddr[3])
        self.fhost = self.fhost + str(nfhost[3])
        self.lhost = self.lhost + str(nlhost[3])
        self.bcast = self.bcast + str(nbcast[3])



I actually need to adapt this for a new project I will be working on shortly to be less of a game/quiz application to something more useful so if you modify it can you post your new script for me to reference?

This post has been edited by blank_program: 10 August 2012 - 03:41 PM

Was This Post Helpful? 0
  • +
  • -

#11 chickensevil  Icon User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 9
  • Joined: 28-July 12

Re: IP Range to Proper Subnetting - Not quite there

Posted 10 August 2012 - 06:41 PM

Hmmm in retrospec it may have actually been better if I had coded it as a class instead... Would have saved me a lot of copy and pasting, since I have moved around files a bunch now. I started down one thing, and as I have been trying to figure the best way to accomplish the overall project, I am up to 14 different files, each doing something slightly different but all along the same lines.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1