Implement IP Address Arithmetic
OpenAISoftware Engineer · OnsiteLast updated
Implement parsing, binary representation, arithmetic offsets, and canonical formatting for both IPv4 and IPv6 addresses and CIDR subnets.
Problem Statement
Design an IP arithmetic utility that parses, manipulates, and formats both IPv4 and IPv6 addresses and CIDR blocks without using built-in networking libraries (e.g., ipaddress, socket.inet_ntop).
Your utility must support the following methods:
add_offset(ip: str, offset: int) -> str: Parses the given IP string (IPv4 or IPv6), adds an integeroffset(which can be positive or negative), and returns the resulting IP address formatted canonically. If the resulting IP falls outside the valid range for its address family ([0, 2^32 - 1]for IPv4,[0, 2^128 - 1]for IPv6), raise aValueError.cidr_info(cidr: str) -> tuple[str, str, int]: Parses a CIDR block (e.g.,"192.168.1.0/24"or"2001:db8::/120") and returns a tuple(network_address, broadcast_address, total_hosts)where all addresses are in their canonical string representations andtotal_hostsis the total count of addresses in the block (2^(bits - prefix)).contains(cidr: str, ip: str) -> bool: ReturnsTrueif the specified IP address belongs to the CIDR block, andFalseotherwise. If the IP version ofipdoes not match the CIDR block's version, raise aValueError.
Formatting Requirements
- IPv4: Standard dotted-quad notation with four decimal integers in
[0, 255]separated by dots (e.g.,"192.168.1.1"). Leading zeros in octets are not allowed. - IPv6: Standard RFC 5952 canonical format:
- Lowercase hexadecimal characters.
- Leading zeros within a 16-bit hextet must be suppressed (e.g.,
:0042:becomes:42:). - The longest run of two or more consecutive all-zero hextets must be replaced with
::. If there is a tie for the longest run, shorten the first one. - Single zero hextets must not be compressed as
::(e.g.,"2001:db8:0:1:1:1:1:1").
Function Interface
class IPArithmetic:
def add_offset(self, ip: str, offset: int) -> str:
pass
def cidr_info(self, cidr: str) -> tuple[str, str, int]:
pass
def contains(self, cidr: str, ip: str) -> bool:
pass
Examples
Example 1
ipa = IPArithmetic()
ipa.add_offset("192.168.1.254", 2)
# Returns: "192.168.2.0"
ipa.cidr_info("192.168.1.0/30")
# Returns: ("192.168.1.0", "192.168.1.3", 4)
ipa.contains("192.168.1.0/24", "192.168.1.42")
# Returns: True
Example 2
ipa = IPArithmetic()
ipa.add_offset("2001:db8::", 1)
# Returns: "2001:db8::1"
ipa.cidr_info("2001:db8::/126")
# Returns: ("2001:db8::", "2001:db8::3", 4)
ipa.add_offset("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 1)
# Raises: ValueError (overflow)
Constraints
- IPv4 prefix lengths:
0 <= prefix <= 32 - IPv6 prefix lengths:
0 <= prefix <= 128 -2^128 <= offset <= 2^128- Built-in networking packages (
ipaddress,socket,urllib) are strictly prohibited.
Hints
Hint 1
Convert both IPv4 and IPv6 addresses into raw unsigned integers (32-bit or 128-bit) before performing arithmetic or bitwise masking.
Hint 2
When expanding an IPv6 string containing `::`, determine how many 16-bit hextets are present on each side of the double-colon to fill in the missing zero hextets.
Hint 3
For RFC 5952 IPv6 compression, find the contiguous sub-array of zeros with the maximum length (must be >= 2) and replace only the first occurrence of that maximal run with `::`.
Follow-up questions
- How would you handle mixed IPv4-mapped IPv6 addresses (e.g., `::ffff:192.0.2.128`)?
- How can you optimize subnet-membership queries if you need to match millions of incoming IP addresses against thousands of CIDR blocks in real time?
- How would you implement CIDR aggregation (route summarization) given a list of arbitrary, overlapping IPv4 or IPv6 subnets?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.