def verbose_ping(address, count=4, interval=1, timeout=2, id=PID): # A payload of 56 bytes is used by default. You can modify it using # the 'payload_size' parameter of your ICMP request. print(f'PING {address}: 56 data bytes\n') # We detect the socket to use from the specified IP address if is_ipv6_address(address): sock = ICMPv6Socket() else: sock = ICMPv4Socket() for sequence in range(count): # We create an ICMP request request = ICMPRequest( destination=address, id=id, sequence=sequence) try: # We send the request sock.send(request) # We are awaiting receipt of an ICMP reply reply = sock.receive(request, timeout) # We received a reply # We display some information print(f' {reply.bytes_received} bytes from ' f'{reply.source}: ', end='') # We throw an exception if it is an ICMP error message reply.raise_for_status() # We calculate the round-trip time and we display it round_trip_time = (reply.time - request.time) * 1000 print(f'icmp_seq={sequence} ' f'time={round(round_trip_time, 3)} ms') # We wait before continuing if sequence < count - 1: sleep(interval) except TimeoutExceeded: # The timeout has been reached print(f' Request timeout for icmp_seq {sequence}') except ICMPError as err: # An ICMP error message has been received print(err) except ICMPLibError: # All other errors print(' An error has occurred.') print('\nCompleted.')
def verbose_traceroute(address, count=2, interval=0.05, timeout=2, id=PID, max_hops=30): # We perform a DNS resolution of the address passed in parameters. # If the address is already an IP address, no lookup is done. The # same address is returned. ip_address = resolve(address) # A payload of 56 bytes is used by default. You can modify it using # the 'payload_size' parameter of your ICMP request. print(f'Traceroute to {address} ({ip_address}): ' f'56 data bytes, {max_hops} hops max\n') # We detect the socket to use from the specified IP address if is_ipv6_address(ip_address): sock = ICMPv6Socket() else: sock = ICMPv4Socket() ttl = 1 host_reached = False while not host_reached and ttl <= max_hops: for sequence in range(count): # We create an ICMP request request = ICMPRequest( destination=ip_address, id=id, sequence=sequence, ttl=ttl) try: # We send the request sock.send(request) # We are awaiting receipt of an ICMP reply reply = sock.receive(request, timeout) # We received a reply # We display some information source_name = getfqdn(reply.source) print(f' {ttl:<2} {reply.source:15} ' f'{source_name:40} ', end='') # We throw an exception if it is an ICMP error message reply.raise_for_status() # We reached the destination host # We calculate the round-trip time and we display it round_trip_time = (reply.time - request.time) * 1000 print(round(round_trip_time, 2), 'ms') # We can stop the search host_reached = True break except TimeExceeded as err: # An ICMP Time Exceeded message has been received # The message was probably generated by an intermediate # gateway reply = err.reply # We calculate the round-trip time and we display it round_trip_time = (reply.time - request.time) * 1000 print(round(round_trip_time, 2), 'ms') sleep(interval) break except TimeoutExceeded: # The timeout has been reached and no host or gateway # has responded after multiple attempts if sequence >= count - 1: print(f' {ttl:<2} * * *') except ICMPLibError: # Other errors are ignored pass ttl += 1 print('\nCompleted.')
def do_one_ping( host, progress: Progress, cc: Optional[str] = None, seq_offset=0, count=8, interval=0.1, timeout=2, id=PID, source=None, **kwargs, ) -> PingResult: """ :raises NameLookupError: If you pass a hostname or FQDN in parameters and it does not exist or cannot be resolved. :raises SocketPermissionError: If the privileges are insufficient to create the socket. :raises SocketAddressError: If the source address cannot be assigned to the socket. :raises ICMPSocketError: If another error occurs. See the `ICMPv4Socket` or `ICMPv6Socket` class for details. """ address = resolve(host) if isinstance(address, list): address = address[0] log = logging.getLogger("rich") task_id = progress.add_task(host, total=count) # on linux `privileged` must be True if is_ipv6_address(address): sock = ICMPv6Socket(address=source, privileged=True) else: sock = ICMPv4Socket(address=source, privileged=True) times = [] for sequence in range(count): progress.update(task_id, advance=1) request = ICMPRequest( destination=address, id=id, sequence=sequence + seq_offset, **kwargs ) try: sock.send(request) reply = sock.receive(request, timeout) reply.raise_for_status() round_trip_time = (reply.time - request.time) * 1000 times.append(round_trip_time) if sequence < count - 1: sleep(interval) except ICMPLibError as e: log.error(f"接收 {host} Ping 返回信息失败: {e}") progress.remove_task(task_id=task_id) sock.close() log.info(f"{host} Ping 检测已经完成") return PingResult(host=host, cc=cc, count=count, times=times)
def do_traceroute( table: Table, address: str, count: int = 2, interval: float = 0.05, timeout: int = 3, id: int = PID, first_hop: int = 1, max_hops: int = 32, source: Optional[str] = None, fast: bool = False, **kwargs, ) -> List[Hop]: """ :param table: rich 动态表格 参数的含义与: `icmplib.traceroute` 保持一致 """ address = resolve(address) address = address[0] if isinstance(address, list) else address sock = ICMPv6Socket(source) if is_ipv6_address(address) else ICMPv4Socket(source) ttl = first_hop host_reached = False hops = [] while not host_reached and ttl <= max_hops: hop_address = None packets_sent = 0 rtts: List[float] = [] for sequence in range(count): request = ICMPRequest( destination=address, id=id, sequence=sequence, ttl=ttl, **kwargs ) reply: Optional[ICMPReply] = None try: sock.send(request) packets_sent += 1 reply = sock.receive(request, timeout) reply.raise_for_status() host_reached = True except TimeExceeded: sleep(interval) except ICMPLibError: continue assert reply is not None hop_address = reply.source round_trip_time = (reply.time - request.time) * 1000 rtts.append(round_trip_time) if fast: break if len(rtts) > 0: hop = Hop( address=hop_address, packets_sent=packets_sent, distance=ttl, rtts=rtts ) hops.append(hop) ip_info = get_ip_info(hop.address) if ip_info is None: position = "" isp = "" else: position = f"{ip_info.country} {ip_info.regionName} {ip_info.city}" isp = f"{ip_info.isp}" table.add_row( f"{hop.address}", # 地址 position, # 位置 isp, # ISP f"{min(hop.rtts):.2f}", # min f"{mean(hop.rtts):.2f}", # avg f"{max(hop.rtts):.2f}", # max ) else: table.add_row("*", "*", "*", "*", "*", "*") ttl += 1 sock.close() return hops
def do_traceroute_v2( host: str, count: int = 2, interval: float = 0.05, timeout: int = 3, id: int = PID, first_hop: int = 1, max_hops: int = 32, source: Optional[str] = None, fast: bool = False, **kwargs, ) -> TraceResult: """ :param table: rich 动态表格 参数的含义与: `icmplib.traceroute` 保持一致 """ address = resolve(host) if isinstance(address, list): address = address[0] if is_ipv6_address(address): sock = ICMPv6Socket(source) else: sock = ICMPv4Socket(source) ttl = first_hop host_reached = False hops: List[TraceHop] = [] while not host_reached and ttl <= max_hops: hop_address = None packets_sent = 0 packets_received = 0 times: List[float] = [] for sequence in range(count): request = ICMPRequest(destination=address, id=id, sequence=sequence, ttl=ttl, **kwargs) reply: Optional[ICMPReply] = None try: sock.send(request) packets_sent += 1 reply = sock.receive(request, timeout) reply.raise_for_status() host_reached = True except TimeExceeded: sleep(interval) except ICMPLibError: continue assert reply is not None hop_address = reply.source packets_received += 1 round_trip_time = (reply.time - request.time) * 1000 times.append(round_trip_time) if fast: break if packets_received: ip_info = get_ip_info(hop_address) info = ip_info.dict() if ip_info is not None else dict() hop = TraceHop(ip=hop_address, distance=ttl, count=count, times=times, info=info) hops.append(hop) ttl += 1 sock.close() return TraceResult(results=hops, host=host)