how do you convert to cidr in python3? - python

I have an ip address 1.2.3.4 with a subnet mask 255.255.255.0
I want to convert this to cidr notation
1.2.3.4/24
How do I do this in Python3?

Use the ipaddress module in the standard library.
An address plus a netmask is either a network or an interface, not an address. Given that you've got some of the host bits set (it's 1.2.3.4, not 1.2.3.0), either you've got an interface, or you've got a non-canonical name for a network; I'll assume it's an interface, so use ip_interface:
>>> i = ipaddress.ip_interface('1.2.3.4/255.255.255.0')
Or, if you want to make sure it's explicitly IPv4 not IPv6:
>>> i = ipaddress.IPv4Interface('1.2.3.4/255.255.255.0')
Or you can compose it out of an address and a network, instead of out of a combined string. It depends on what format you have this information in and what makes sense to you.
To get the CIDR format, use the with_prefixlen accessor:
>>> i.with_prefixlen
'1.2.3.4/24'
You can also do all kinds of other nifty things—extract the address (1.2.3.4) as i.address, or the network (1.2.3.0/24) as i.network, or enumerate all the addresses on the network by treating i.network as a sequence, etc.

You can use the IPy library to do this. If you scroll down to the documentation you can see the string conversions it can do. The one we're after is strNormal(1)
IP("1.2.3.4/255.255.255.0").strNormal(1)

Related

Calculate which subnets an IP address belongs to

I'm kind of stuck on a particular issue. I need to calculate the subnets an IP address belongs to. It could be done in SQL or Python or similar.
So if I have e.g. 100.100.100.105 I need to get all the subnets:
100.100.100.105/32
100.100.100.104/31
100.100.100.104/30
100.100.100.104/29
100.100.100.96/28
100.100.100.96/27
100.100.100.64/26
...
100.64.0.0/10
100.0.0.0/9
...
64.0.0.0/2
0.0.0.0/1
But really don't know how to approach the issue.
you can achieve this with the python3 built in ipaddress module
import ipaddress
addresses = []
# get the int representation of your ip
ip = int(ipaddress.IPv4Address('100.100.100.105'))
for mask in range(32):
addresses.append(f'{ipaddress.IPv4Address(ip & ((2**32-1)-(2**mask -1)))}/{32-mask }')
At each iteration, we apply the mask to our IP by doing a logic AND operation between the integer representations of the IP and the mask. We then convert the result to ip octets and append the '/24' subnet notation. You can replace 2**32-1 with 4294967295, I left it there so its clearer what is happening.

Trying to replace last 2 octets of ip address

I have the following ip address "192.168.2.65"
Is there a way to convert the last 2 octets to 0.
I found the following, but it only lets me replace the last one, i need to replace the last 2.
ip = 192.168.2.65
output='.'.join(ip.split('.')[:-1]+["0"])
print(output)
which gives me 192.168.2.0 and i would like to be 192.168.0.0
Index -1 means the last index. If you want to change two, change your index to -2.
output='.'.join(ip.split('.')[:-2]+["0", "0"])
You could also use a regex based approach here:
ip = "192.168.2.65"
output = re.sub(r'\.\d+\.\d+$', '.0.0', ip)
print(output) # prints 192.168.0.0
Dependant on the logic you are trying to apply.. if you are simply wanting to modify a string, the other answers are correct.
However, if you are looking to get the network address for the subnet an address resides in, you should handle the addresses correctly and use the ipaddress module.
This will assist in calculating the correct network & broadcast addresses, and allow you to check inclusions in networks etc.
import ipaddress
interface = IPv4Interface('192.168.2.35/255.255.0.0')
print(interface.network)
#192.168.0.0/16
print(interface.network.network_address)
#192.168.0.0
print(interface.network.broadcast_address)
#192.168.255.255

IPv6 address assignment in the 0::/8 range

I need to know if the address in the range 0::/96 can be actually assigned in IPv6 or not.
I've found the reference on IANA that IANA can't assign that range (actually 0::/8 range) but I can't find it as being an actually "reserved" range.
My issue is that I'm converting IP Addresses from integers on python. Using the standard library ipaddress which has a convenient factory method ip_address that applies the simple heuristic, if n < 2**32 then ipv4 else ipv6.
This heurisitc would be great if I could find a place in which it screams out to networks admins to forbid using this range xD
Anyway, thanks!
You can find what you are looking for in RFC 5156. Section 2.3 lists the "IPv4-Compatible Addresses" which have been deprecated:
These addresses are deprecated and should not appear on the public Internet
And if you should see them they represent an IPv4 address (except for ::1), so a n > 1 && n < 2**32 heuristic should be perfectly safe.

Binary to String

I am trying to write an IP address program in Python. However, when I use a mask that's less than 7 to get the network ID, I get strange numbers. For example for IP address 164.36.32.32 and subnet mask 6 I get 43.0.0.0. Note that netmask contains the whole IP address in binary.
if mask<=8:
print int(netmask[0:mask],2),".0.0.0"
elif mask>8 and mask<=16:
print int(netmask[0:8],2),".",int(netmask[8:mask],2)
elif mask>16 and mask<=24:
print int(netmask[0:8],2),".",int(netmask[8:16],2),".",int(netmask[16:mask],2)
elif mask>24 and mask<=32:
print int(netmask[0:8],2),".",int(netmask[8:16],2),".",int(netmask[16:24],2),".",int(netmask[24:mask],2),
Python's standard library contains the ipaddress module, which will do most common operations on IP addresses. From your code it seems that your "binary" representation of the IP address is actually a string made up of ones and zeroes. This is not only going to be much less efficient than using integers but also you are going to be using a load more memory than you need. Specifically the information at http://docs.python.org/dev/library/ipaddress#ipaddress.IPv4Interface.network might help. Since this appears to be a learning exercise, though, we might take a look at using your current representation.
I assume you failed to append ".0.0" in the second case and ".0" in the third one.
The best way to perform masking operations, whether using strings or integers, is to deal with the bits first and then translate the bit form into your preferred representation. It is relatively easy to define a function to translate a string of 32 bits into dotted-quad notation. It is also not difficult to build a function to mask an address by retaining only the bits indicated by a network prefix.
address = "11110000110011001010101010100001"
assert len(address) == 32
def dotted_quad(address):
return ".".join(str(int(address[i*8:(i+1)*8], 2)) for i in range(4))
def net_address(address, prefix):
return dotted_quad(address[:prefix]+"0"*(32-prefix))
print dotted_quad(address)
for prefix in range(32):
print net_address(address, prefix)
This prints
240.204.170.161
0.0.0.0
128.0.0.0
192.0.0.0
224.0.0.0
240.0.0.0
240.0.0.0
240.0.0.0
240.0.0.0
240.0.0.0
240.128.0.0
240.192.0.0
240.192.0.0
240.192.0.0
240.200.0.0
240.204.0.0
240.204.0.0
240.204.0.0
240.204.128.0
240.204.128.0
240.204.160.0
240.204.160.0
240.204.168.0
240.204.168.0
240.204.170.0
240.204.170.0
240.204.170.128
240.204.170.128
240.204.170.160
240.204.170.160
240.204.170.160
240.204.170.160
240.204.170.160
which would seem to be doing what you want.

CIDR subnet calculation and python ipcalc

I am questioning the results of the ipcalc module (ipcalc) for Python (it seems that netaddr may be a better choice).
Let's take 192.168.1.25/30 as an example. In binary, the last octet is 00011001 AND 11111100 = 00011000, so I get 192.168.1.24 as the Network ID and the range 192.168.1.24 - 192.168.1.27.
Using ipcalc, when I specify
subnet = ipcalc.Network('192.168.1.25/30')
for x in subnet: print x
The output is
192.168.1.25
192.168.1.26
192.168.1.27
192.168.1.28
I am not understanding the inconsistency. When using CIDR notation, it seems that specifying both 192.168.1.24/30 and 192.168.1.25/30 (or .26/30 or .27/30) refer to the same subnet.
Is that correct? Is this just a bug in the ipcalc module?
There is an open bug for this at the moment: No way to resolve IP + Netmask to Network Object
And an earlier bug report that discuss the matter: Strange subnet calculations
But they have also added a function called network to get the network address from an IP. From the manual:
>>> localnet = Network('127.128.99.3/8')
>>> print localnet.network()
127.0.0.0
The manual specifically says that the constructor Network should take a network address as its first argument, not any IP in the network. Rather confusing if you ask me (especially since the above code block breaks that condition). I would at least read the code for the module before using it.
It's correct the subnet is 192.168.1.24/30 so the ips 192.168.1.24 to 192.168.1.27 make part of this network.

Categories