Supercharge Your Network Operations with Netutils

Supercharge Your Network Operations with Netutils 

Introduction 

Netutils is a Python library built to simplify everyday network automation. It provides a set of utilities and classes that take care of tedious tasks engineers would rather avoid—like using regular expressions to match and standardize interface names—so you can focus on more valuable work.

What Is Netutils?

Netutils is a Python package that offers: 

  • Interface name standardization (i.e., it standardizes network interface names across different platforms)
  • MAC address formatting and validation 
  • IP address calculation and subnet operations (more lightweight than the ipaddress standard library and more network automation focused) 
  • Network protocol helpers that convert port numbers to protocol names, protocol names to port numbers, and other helper functions
  • Reliable network utility functions without reinventing the wheel
  • And much more! 

Check out common use cases in the Netutils Documentation

Who Is Netutils For?

Netutils is designed for: 

  • Network Engineers who are automating their infrastructure
  • DevOps Engineers working with network automation
  • Python Developers building network tools
  • Anyone who needs to perform common network operations in Python

Installation

Let’s work on some simple examples using netutils. Of course, we need to install netutils, preferably in a virtual environment:

#pip install netutils

Examples

1. Interface name standardization

As engineers, we know that Gi0/1 and GigabitEthernet0/1, or Eth1 and Ethernet1 refer to the same interface. Computers, however, treat them as different values. In this example, we’ll show how Netutils can standardize interface names, converting shorthand variations into a consistent format.

#interface_example.py

#!/usr/bin/env python3
"""Examples of using netutils interface name standardization functions.

This script demonstrates how to use netutils to standardize and abbreviate
network interface names across different platforms.
"""

from netutils.interface import canonical_interface_name, abbreviated_interface_name

def main():
    """Run interface name standardization examples."""
    print("Interface Name Standardization Examples:")
    print("-" * 40)
    
    # Convert interface names to canonical form
    print("\nCanonical Interface Names:")
    print(f"Gi0/1 -> {canonical_interface_name('Gi0/1')}")
    print(f"Eth1 -> {canonical_interface_name('Eth1')}")
    print(f"Po40 -> {canonical_interface_name('Po40')}")
    print(f"Lo10 -> {canonical_interface_name('Lo10')}")
    
    # Convert to abbreviated form
    print("\nAbbreviated Interface Names:")
    print(f"GigabitEthernet0/1 -> {abbreviated_interface_name('GigabitEthernet0/1')}")
    print(f"Port-channel40 -> {abbreviated_interface_name('Port-channel40')}")

if __name__ == "__main__":
    main()

Here is the output of the example

# python interface_examples.py 
Interface Name Standardization Examples:
----------------------------------------

Canonical Interface Names:
Gi0/1 -> GigabitEthernet0/1
Eth1 -> Ethernet1
Po40 -> Port-channel40
Lo10 -> Loopback10

Abbreviated Interface Names:
GigabitEthernet0/1 -> Gi0/1
Port-channel40 -> Po40

2. IP address operations

The following example demonstrates various common IP address operations using the netutils library, including: 

  • Testing whether or not strings are valid IP addresses for both IPv4 and IPv6
  • Converting IP addresses to different formats between binary and hexadecimal representations 
  • Finding a usable IP address range within a network
  • Checking if a string represents valid IP ranges in formats such as 10.1.1.1 – 10.1.1.10 
  • Determining whether a specific IP address falls within a network subnet 

#ip_examples.py

#!/usr/bin/env python3
"""Examples of using netutils IP address operations.

This script demonstrates various IP address operations using the netutils library.
"""

import ipaddress
from netutils.ip import (
    is_ip,
    ip_to_bin,
    ip_to_hex,
    get_usable_range,
    get_first_usable,
    is_network,
    is_ip_range,
    is_ip_within,
)

def main():
    """Run IP address operation examples."""
    print("IP Address Operations Examples:")
    print("-" * 40)
    
    # IP address validation
    print("\nIP Address Validation:")
    test_ips = [
        "10.1.1.1",
        "2001:db8::1",
        "256.1.1.1",  # Invalid IPv4
        "not.an.ip",
    ]
    for ip in test_ips:
        if is_ip(ip):
            ip_obj = ipaddress.ip_address(ip)
            version = "IPv4" if ip_obj.version == 4 else "IPv6"
            print(f"{ip} is a valid {version} address")
        else:
            print(f"{ip} is not a valid IP address")
    
    # IP address conversion
    print("\nIP Address Conversion:")
    ip = "10.1.1.1"
    print(f"IP: {ip}")
    print(f"Binary: {ip_to_bin(ip)}")
    print(f"Hexadecimal: {ip_to_hex(ip)}")
    
    # Network range operations
    print("\nNetwork Range Operations:")
    network = "10.1.1.0/24"
    print(f"Network: {network}")
    print(f"Usable range: {get_usable_range(network)}")
    print(f"First usable IP: {get_first_usable(network)}")
    
    # IP range validation
    print("\nIP Range Validation:")
    ranges = [
        "10.1.1.1-10.1.1.10",
        "10.1.1.10-10.1.1.1",  # Invalid (end < start)
        "not.a.range",
    ]
    for ip_range in ranges:
        if is_ip_range(ip_range):
            print(f"{ip_range} is a valid IP range")
        else:
            print(f"{ip_range} is not a valid IP range")
    
    # IP within range check
    print("\nIP Within Range Check:")
    ip = "10.1.1.5"
    ranges = [
        "10.1.1.0/24",
        "10.1.1.1-10.1.1.10",
        "10.1.2.0/24",
    ]
    for range_str in ranges:
        if is_ip_within(ip, range_str):
            print(f"{ip} is within {range_str}")
        else:
            print(f"{ip} is not within {range_str}")

if __name__ == "__main__":
    main()

Below is the executed output from the script above: 

# python ip_examples.py 
IP Address Operations Examples:
----------------------------------------

IP Address Validation:
10.1.1.1 is a valid IPv4 address
2001:db8::1 is a valid IPv6 address
256.1.1.1 is not a valid IP address
not.an.ip is not a valid IP address

IP Address Conversion:
IP: 10.1.1.1
Binary: 00001010000000010000000100000001
Hexadecimal: 0a010101

Network Range Operations:
Network: 10.1.1.0/24
Usable range: 10.1.1.1 - 10.1.1.254
First usable IP: 10.1.1.1

IP Range Validation:
10.1.1.1-10.1.1.10 is a valid IP range
10.1.1.10-10.1.1.1 is not a valid IP range
not.a.range is not a valid IP range

IP Within Range Check:
10.1.1.5 is within 10.1.1.0/24
10.1.1.5 is within 10.1.1.1-10.1.1.10
10.1.1.5 is not within 10.1.2.0/24

3. MAC address operations

The following example demonstrates various common MAC address operations using the netutils library, including: 

  • Testing if a string is a valid MAC address in different formats, for example, colon-separated, dash-separated, dot-separated, etc.
  • Converting MAC addresses between different formats, such as from 00:11:22:33:44:55 to 00-11-22-33-44-55 
  • Using the Organizational Unique Identifier (OUI) within the MAC address to look up the manufacturer 

#mac_examples.py

#!/usr/bin/env python3
"""Examples of using netutils MAC address operations.

This script demonstrates various MAC address operations including validation,
formatting, and vendor lookup using netutils.
"""

from netutils.mac import is_valid_mac, mac_to_format, mac_normalize, get_oui

def main():
    """Run MAC address operation examples."""
    print("MAC Address Operations Examples:")
    print("-" * 40)
    
    # MAC address validation
    print("\nMAC Address Validation:")
    print(f"is_valid_mac('00:11:22:33:44:55') -> {is_valid_mac('00:11:22:33:44:55')}")
    print(f"is_valid_mac('00-11-22-33-44-55') -> {is_valid_mac('00-11-22-33-44-55')}")
    print(f"is_valid_mac('0011.2233.4455') -> {is_valid_mac('0011.2233.4455')}")
    
    # MAC address formatting
    print("\nMAC Address Formatting:")
    mac = "0011.2233.4455"
    print(f"Original MAC: {mac}")
    print(f"MAC_COLON_TWO -> {mac_to_format(mac, 'MAC_COLON_TWO')}")
    print(f"MAC_DASH_TWO -> {mac_to_format(mac, 'MAC_DASH_TWO')}")
    print(f"MAC_DOT_TWO -> {mac_to_format(mac, 'MAC_DOT_TWO')}")
    print(f"MAC_COLON_FOUR -> {mac_to_format(mac, 'MAC_COLON_FOUR')}")
    
    # MAC address normalization
    print("\nMAC Address Normalization:")
    print(f"mac_normalize('00:11:22:33:44:55') -> {mac_normalize('00:11:22:33:44:55')}")
    
    # MAC address vendor lookup
    print("\nMAC Address Vendor Lookup:")
    try:
        print(f"get_oui('cc:79:d7:dd:ee:ff') -> {get_oui('cc:79:d7:dd:ee:ff')}")
    except ValueError as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    main()

Here is the output from the script above:

# python mac_examples.py 
MAC Address Operations Examples:
----------------------------------------

MAC Address Validation:
is_valid_mac('00:11:22:33:44:55') -> True
is_valid_mac('00-11-22-33-44-55') -> True
is_valid_mac('0011.2233.4455') -> True

MAC Address Formatting:
Original MAC: 0011.2233.4455
MAC_COLON_TWO -> 00:11:22:33:44:55
MAC_DASH_TWO -> 00-11-22-33-44-55
MAC_DOT_TWO -> 00.11.22.33.44.55
MAC_COLON_FOUR -> 0011:2233:4455

MAC Address Normalization:
mac_normalize('00:11:22:33:44:55') -> 001122334455

MAC Address Vendor Lookup:
get_oui('cc:79:d7:dd:ee:ff') -> Cisco Systems, Inc

4. Network protocol helpers

The following example demonstrates various common operations regarding network protocols using the netutils library, including:

  • Converting protocol names, such as TCP and UDP, to their respective IP protocol numbers, and vice versa  
  • Converting well-known TCP/UDP service names to port numbers, and vice versa 

#protocol_examples.py

#!/usr/bin/env python3
"""Examples of using netutils protocol helpers.

This script demonstrates how to use netutils protocol mapping functions
to convert between protocol names and numbers.
"""

from netutils.protocol_mapper import (
    PROTO_NAME_TO_NUM,
    PROTO_NUM_TO_NAME,
    TCP_NAME_TO_NUM,
    TCP_NUM_TO_NAME,
    UDP_NAME_TO_NUM,
    UDP_NUM_TO_NAME,
)

def main():
    """Run protocol helper examples."""
    print("Protocol Helper Examples:")
    print("-" * 40)
    
    # Get IP protocol numbers
    print("\nIP Protocol Name to Number:")
    protocols = ["TCP", "UDP", "ICMP", "OSPF", "BGP"]
    for protocol in protocols:
        try:
            number = PROTO_NAME_TO_NUM[protocol]
            print(f"{protocol} -> {number}")
        except KeyError:
            print(f"{protocol} -> Not found")
    
    # Get IP protocol names
    print("\nIP Protocol Number to Name:")
    numbers = [6, 17, 1, 89, 179]
    for number in numbers:
        try:
            name = PROTO_NUM_TO_NAME[number]
            print(f"{number} -> {name}")
        except KeyError:
            print(f"{number} -> Not found")
    
    # Get TCP port numbers
    print("\nTCP Port Name to Number:")
    tcp_ports = ["HTTP", "HTTPS", "SSH", "FTP", "SMTP"]
    for port in tcp_ports:
        try:
            number = TCP_NAME_TO_NUM[port]
            print(f"{port} -> {number}")
        except KeyError:
            print(f"{port} -> Not found")
    
    # Get TCP port names
    print("\nTCP Port Number to Name:")
    tcp_numbers = [80, 443, 22, 21, 25]
    for number in tcp_numbers:
        try:
            name = TCP_NUM_TO_NAME[number]
            print(f"{number} -> {name}")
        except KeyError:
            print(f"{number} -> Not found")
    
    # Get UDP port numbers
    print("\nUDP Port Name to Number:")
    udp_ports = ["DNS", "DHCP", "SNMP", "TFTP", "NTP"]
    for port in udp_ports:
        try:
            number = UDP_NAME_TO_NUM[port]
            print(f"{port} -> {number}")
        except KeyError:
            print(f"{port} -> Not found")
    
    # Get UDP port names
    print("\nUDP Port Number to Name:")
    udp_numbers = [53, 67, 161, 69, 123]
    for number in udp_numbers:
        try:
            name = UDP_NUM_TO_NAME[number]
            print(f"{number} -> {name}")
        except KeyError:
            print(f"{number} -> Not found")

if __name__ == "__main__":
    main()

Here is the output from the script above:

# python protocol_examples.py 
Protocol Helper Examples:
----------------------------------------

IP Protocol Name to Number:
TCP -> 6
UDP -> 17
ICMP -> 1
OSPF -> Not found
BGP -> Not found

IP Protocol Number to Name:
6 -> TCP
17 -> UDP
1 -> ICMP
89 -> OSPFIGP
179 -> Not found

TCP Port Name to Number:
HTTP -> Not found
HTTPS -> 443
SSH -> 22
FTP -> 21
SMTP -> 25

TCP Port Number to Name:
80 -> WWW-HTTP
443 -> HTTPS
22 -> SSH
21 -> FTP
25 -> SMTP

UDP Port Name to Number:
DNS -> Not found
DHCP -> Not found
SNMP -> 161
TFTP -> 69
NTP -> 123

UDP Port Number to Name:
53 -> DOMAIN
67 -> BOOTPS
161 -> SNMP
69 -> TFTP
123 -> NTP

Conclusion

Netutils offers a reliable platform-agnostic toolkit for network automation. Built on Python best practices and thoroughly tested, it’s designed to simplify your work whether you’re writing a quick script or developing a full-scale automation system. Instead of reinventing the wheel, let Netutils handle the fundamentals so you can focus on delivering results.

Additional Resources: 

– Eric Chou



Author