@@ -50,6 +50,106 @@ def throw_error(
5050 raise ValueError (f"Invalid error handling strategy: { errors } " )
5151
5252
53+ def ip_to_tuple (ip : str ) -> tuple [int , int , int , int ]:
54+ """
55+ Converts an IP address string to a tuple of four integers.
56+
57+ Args:
58+ ip (str): The IP address in string format (e.g., "192.168.1.1").
59+
60+ Returns:
61+ tuple[int, int, int, int]: A tuple representing the four octets of the IP address.
62+
63+ Raises:
64+ TypeError: If the input is not a string.
65+ ValueError: If the input is not a valid IP address format.
66+ """
67+ if not isinstance (ip , str ):
68+ raise TypeError (f"Expected string, got { type (ip ).__name__ } " )
69+ try :
70+ ip_tuple = tuple (int (x ) for x in ip .split ("." ))
71+ except ValueError :
72+ raise ValueError (f"Invalid IP address format: { ip } " ) from None
73+ if len (ip_tuple ) != 4 or any (x < 0 or x > 255 for x in ip_tuple ):
74+ raise ValueError (f"Invalid IP address format: { ip } " )
75+ return ip_tuple
76+
77+
78+ def ip_analyze (ip : str ) -> list [str ]:
79+ """
80+ Analyzes an IP address or range and returns a list of valid IP addresses.
81+
82+ Args:
83+ ip (str): The IP address or range in string format (e.g., "192.168.1.1", "192.168.1.1/24", "192.168.1.1-100").
84+
85+ Returns:
86+ list[str]: A list of valid IP addresses.
87+
88+ Raises:
89+ TypeError: If the input is not a string.
90+ ValueError: If the input is not a valid IP address or range.
91+ """
92+ if not isinstance (ip , str ):
93+ raise TypeError (f"Expected string, got { type (ip ).__name__ } " )
94+ ip = ip .replace (" " , "" )
95+ if "/" in ip :
96+ match ip .split ("/" ):
97+ case [ip_addr , mask ]:
98+ if not mask .isdigit ():
99+ raise ValueError (f"Invalid subnet mask: { mask } " )
100+ mask = int (mask )
101+ if mask < 0 or mask > 32 :
102+ raise ValueError (f"Subnet mask out of range: { mask } " )
103+ if mask < 16 :
104+ raise ValueError (f"Subnet mask too small: { mask } " )
105+ case _:
106+ raise ValueError (f"Invalid IP address format: { ip } " )
107+ ip_tuple = ip_to_tuple (ip_addr )
108+ ip32 = ip_tuple [0 ] << 24 | ip_tuple [1 ] << 16 | ip_tuple [2 ] << 8 | ip_tuple [3 ]
109+ ip32 &= (0xFFFFFFFF >> (32 - mask )) << (32 - mask )
110+ return [
111+ f"{ (i >> 24 ) & 0xFF } .{ (i >> 16 ) & 0xFF } .{ (i >> 8 ) & 0xFF } .{ i & 0xFF } "
112+ for i in range (ip32 , ip32 + (1 << (32 - mask )))
113+ ]
114+ if "-" in ip :
115+ ip_range_tuple = ip .split ("." )
116+ if len (ip_range_tuple ) != 4 :
117+ raise ValueError (f"Invalid IP address range format: { ip } " )
118+ ip_count = 1
119+ ip_range : list [tuple [int , int ]] = []
120+ for i in ip_range_tuple :
121+ match i .split ("-" ):
122+ case [single ]:
123+ if not single .isdigit ():
124+ raise ValueError (f"Invalid IP address range format: { ip } " )
125+ single = int (single )
126+ if single < 0 or single > 255 :
127+ raise ValueError (f"IP address out of range: { single } " )
128+ ip_range .append ((single , single ))
129+ case [start , end ]:
130+ if not (start .isdigit () and end .isdigit ()):
131+ raise ValueError (f"Invalid IP address range format: { ip } " )
132+ start = int (start )
133+ end = int (end )
134+ if start < 0 or start > 255 or end < 0 or end > 255 or start > end :
135+ raise ValueError (f"Invalid IP address range: { start } -{ end } " )
136+ ip_range .append ((start , end ))
137+ case _:
138+ raise ValueError (f"Invalid IP address range format: { ip } " )
139+ ip_count *= ip_range [- 1 ][1 ] - ip_range [- 1 ][0 ] + 1
140+ if ip_count > 65536 :
141+ raise ValueError (f"IP address range too large: { ip_count } addresses" )
142+ return [
143+ f"{ a } .{ b } .{ c } .{ d } "
144+ for a in range (ip_range [0 ][0 ], ip_range [0 ][1 ] + 1 )
145+ for b in range (ip_range [1 ][0 ], ip_range [1 ][1 ] + 1 )
146+ for c in range (ip_range [2 ][0 ], ip_range [2 ][1 ] + 1 )
147+ for d in range (ip_range [3 ][0 ], ip_range [3 ][1 ] + 1 )
148+ ]
149+ ip_tuple = ip_to_tuple (ip )
150+ return [f"{ ip_tuple [0 ]} .{ ip_tuple [1 ]} .{ ip_tuple [2 ]} .{ ip_tuple [3 ]} " ]
151+
152+
53153def format_msg (
54154 msg : str ,
55155 * ,
0 commit comments