Example #1
0
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.')
Example #2
0
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.')
Example #3
0
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)
Example #4
0
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)