Python Forum

Full Version: convert address and broadcast to network object
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
the ipaddress module API can convert a network object into the subnet base and broadcast addresses but i cannot find a means to do the reverse, that is, given subnet base and broadcast addresses, convert that into a network object. anyone know the API to do that?
By "subnet base", do you meant the CIDR size or the subnet mask or something else?

Can do it with the netaddr module.

>>> from netaddr import IPNetwork
>>> n = IPNetwork("192.0.0.255/24")
>>> n.network
IPAddress('192.0.0.0')
not the size. not the mask. just the base. for 192.168.0.0/16 the base is 192.168.0.0 and the broadcast is 192.168.255.255. the network size is 65536. the number of hosts is 65534. the net mask is 255.255.0.0. the network bit length is 16.

so, if i have 192.168.0.0 and 192.168.255.255 i want to get 192.168.0.0/16. i have done this in C. i could do it in Python by converting these address to int and work on them that way with some ugly code. ipaddress has just about everything else, almost everything i need. but it seems to be missing this one thing.

i don't see netaddr in my PDF doc. i last downloaded 3.7.4 PDFs. apparently i need some newer ones. i'm running 3.8.10 so my PDFs are not that far behind. i had planned to download the 3.10 PDFs when i upgrade to Ubuntu 22.04 (uses Python 3.10) or 24.04 (unknown Python).
3.8.10 has no netaddr. so i guess i am stuck with ipaddress for now. maybe i just need to stuff all the ugly code into a function. the use of the function would be clear code and potentially pythonic. can't say the same for the function itself. maybe i can name it ip_base_bcst_to_network().
If you have the base and the broadcast, then you can get the host size from xor of the two. Then you can manipulate to get the cidr size. An example for ipv4 might be:

>>> base = ipaddress.ip_address('192.168.128.0')
>>> broadcast = ipaddress.ip_address('192.168.255.255')
>>> cidr_length = 32 - (int.from_bytes(base.packed, 'big') ^ int.from_bytes(broadcast.packed,'big')).bit_length()
>>> cidr_length
17
It works and yes .... it's a bit nested :-/
Take what you need.


import sys
import ipaddress


def interface(interface):
    interface = ipaddress.ip_interface(interface)
    ip = interface.ip
    ip_version = ip.version
    ptr = ip.reverse_pointer
    network = interface.network
    network_addr = network.network_address
    netmask = interface.netmask
    hostmask = interface.hostmask
    broadcast = network.broadcast_address
    return {
        "ip": str(ip),
        "ip_version": ip_version,
        "private": ip.is_private,
        "global": ip.is_global,
        "ptr": ptr,
        "network_addr": str(network_addr),
        "netmask": str(netmask),
        "hostmask": str(hostmask),
        "broadcast": str(broadcast),
    }


print(sys.version)
print()

some_interfaces = [
    "192.168.0.1/24",
    "192.168.172.10/24",
    "192.168.178.10/24",
    "10.10.1.5/16",
    "fd00::ffff:ac10:1/112",
    "1.2.3.4/23",
]

for result in map(interface, some_interfaces):
    print("Processing ip", result["ip"])
    print()
    for key, value in result.items():
        key = f"{key}:"
        print(f"{key:<15} -> {value}")
    print()
Output:
Output:
3.8.16 (default, Mar 8 2023, 22:40:51) [GCC 12.2.1 20230201] Processing ip 192.168.0.1 ip: -> 192.168.0.1 ip_version: -> 4 private: -> True global: -> False ptr: -> 1.0.168.192.in-addr.arpa network_addr: -> 192.168.0.0 netmask: -> 255.255.255.0 hostmask: -> 0.0.0.255 broadcast: -> 192.168.0.255 Processing ip 192.168.172.10 ip: -> 192.168.172.10 ip_version: -> 4 private: -> True global: -> False ptr: -> 10.172.168.192.in-addr.arpa network_addr: -> 192.168.172.0 netmask: -> 255.255.255.0 hostmask: -> 0.0.0.255 broadcast: -> 192.168.172.255 Processing ip 192.168.178.10 ip: -> 192.168.178.10 ip_version: -> 4 private: -> True global: -> False ptr: -> 10.178.168.192.in-addr.arpa network_addr: -> 192.168.178.0 netmask: -> 255.255.255.0 hostmask: -> 0.0.0.255 broadcast: -> 192.168.178.255 Processing ip 10.10.1.5 ip: -> 10.10.1.5 ip_version: -> 4 private: -> True global: -> False ptr: -> 5.1.10.10.in-addr.arpa network_addr: -> 10.10.0.0 netmask: -> 255.255.0.0 hostmask: -> 0.0.255.255 broadcast: -> 10.10.255.255 Processing ip fd00::ffff:ac10:1 ip: -> fd00::ffff:ac10:1 ip_version: -> 6 private: -> True global: -> False ptr: -> 1.0.0.0.0.1.c.a.f.f.f.f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa network_addr: -> fd00::ffff:ac10:0 netmask: -> ffff:ffff:ffff:ffff:ffff:ffff:ffff:0 hostmask: -> ::ffff broadcast: -> fd00::ffff:ac10:ffff Processing ip 1.2.3.4 ip: -> 1.2.3.4 ip_version: -> 4 private: -> False global: -> True ptr: -> 4.3.2.1.in-addr.arpa network_addr: -> 1.2.2.0 netmask: -> 255.255.254.0 hostmask: -> 0.0.1.255 broadcast: -> 1.2.3.255
@DeaD_EyE:
it looks like you are implementing an interface object from an ipaddress object. where do i provide the two numeric values (base and broadcast in the same address version) i have, such as '172.16.0.0' and '172.31.255.255' to get a network object (of either address version) equivalent to '172.16.0.0/12' in this case?
(Mar-09-2023, 01:09 AM)Skaperen Wrote: [ -> ]where do i provide the two numeric values (base and broadcast in the same address version) i have, such as '172.16.0.0' and '172.31.255.255' to get a network object (of either address version) equivalent to '172.16.0.0/12' in this case?
An ignorant's proposal: try out every possibility
from ipaddress import *

def my_network(address, broadcast):
    a = IPv4Address(broadcast)
    for i in range(33):
        try:
            n = IPv4Network(f'{address}/{i}')
        except ValueError:
            continue
        if n.broadcast_address == a:
            return n
    raise ValueError(address, broadcast)

if __name__ == '__main__':
    n = my_network('172.16.0.0', '172.31.255.255')
    print(n)
Output:
172.16.0.0/12
This tutorial may help perhaps.
Hmm, after reading this page about CIDR, I suggest this
>>> from ipaddress import *
>>> a = IPv4Address('172.31.255.255')
>>> b = IPv4Address('172.16.0.0')
>>> 32 - (int(a) - int(b)).bit_length()
12
i think my C solution was the try every possibility. so maybe i need to go back and fix some C code.