@@ -198,25 +198,42 @@ def seconds_to_timespan(seconds: int) -> str:
198198 return f"{ d :02d} :{ h :02d} :{ m :02d} :{ s :02d} :00"
199199
200200
201- def ip_to_ptr (ip_address : str ) -> str :
201+ def ip_to_ptr (ip_address : str , prefixlen : int | None = None ) -> str :
202202 """
203203 Get the reverse pointer from given address.
204204
205205 :param ip_address: Address.
206206 :type ip_address: str
207+ :param prefixlen: Prefix length, optional
208+ :type prefixlen: int | None = None
207209 :return: Reverse pointer.
208210 :rtype: str
209211 """
210212 ip = ipaddress .ip_address (ip_address )
213+ network = ipaddress .ip_network (ip )
214+
215+ if prefixlen is not None :
216+ network = network .supernet (new_prefix = prefixlen )
217+ elif ip .version == 4 :
218+ prefixlen = 24
219+ else :
220+ prefixlen = 64
221+
222+ if prefixlen > network .max_prefixlen :
223+ raise ValueError (f"Prefix { prefixlen } too large for { ip .version } !" )
224+
225+ subnet = network .supernet (new_prefix = prefixlen )
226+
211227 if ip .version == 4 :
212- octets = ip .packed
213- ptr = f"{ octets [2 ]} .{ octets [1 ]} .{ octets [0 ]} .in-addr.arpa."
214- elif ip .version == 6 :
215- hex_parts = ip .exploded .replace (":" , "" ).lower ()
216- ptr = f"{ hex_parts [::- 1 ]} .ip6.arpa."
228+ octets = subnet .network_address .packed
229+ parts = [str (octets [i ]) for i in range ((prefixlen // 8 ) - 1 , - 1 , - 1 )]
230+ return "." .join (parts ) + ".in-addr.arpa"
217231 else :
218- raise ValueError ("Unsupported IP version" )
219- return ptr
232+ hex_str = subnet .network_address .exploded .replace (":" , "" ).lower ()
233+ nibbles = list (hex_str )
234+ relevant_nibbles = nibbles [: prefixlen // 4 ]
235+ reversed_nibbles = "." .join (relevant_nibbles [::- 1 ])
236+ return f"{ reversed_nibbles } .ip6.arpa"
220237
221238
222239def ip_version (ip_address : str ) -> int | None :
0 commit comments