0

我想实现基本的网络检查功能来测试提供的 url 是否响应(例如ping www.google.com)。它必须提供操作信息,例如,请求的服务不可用或主机无法到达。我可以使用icmp4j库来实现它。但我想使用pcap4j库来实现相同的目标。我想将 url 放在文本框中,然后单击连接按钮,该按钮将调用 pcap4j api 来检查主机是否响应。

4

2 回答 2

0

我花了一年多的时间才弄清楚这一点,因为我想用 pcap4j 做一个 traceroute,所以这就是我所做的:

  1. 获取您的 IPv4 地址和 Mac 地址,这可以通过查询PcapNetworkInterface
  2. 获取目标 IP 地址,如果您有 DNS 名称,则需要事先解析它。
  3. 获取目标 Mac 地址。
    1. 目标在同一个子网中:发送一个 ARP 请求来解析 mac(或者,mac 广播也可以正常工作)。
    2. 目标在不同的子网中:您需要获取网关服务器的mac,这并不容易。假设您有其他网络流量正在进行,您可以侦听传入的数据包并获取源 mac,其中源 IP 地址来自不同的子网,这可能是网关服务器的 mac 地址。
  4. 创建IcmpV4EchoPacket并发送
  5. 侦听传入的 ICMP 流量,您将获得以下三个之一:
    1. IcmpV4EchoReplyPacket可能是对您请求的答复(请检查标识符和序列号以确保)
    2. AIcmpV4TimeExceededPacket如果在您指定的生存时间内无法达到目标
    3. 什么都没有,路由器和 ping 的目标可以随意忽略并且不回答您的请求

需要填写的变量:

short IDENTIFIER; // identifer may be any 16 bit interger
short SEQUENCE; // sequence may be any 16 bit integer
byte TTL; // time to live (1-255)
Inet4Address IP_TARGET; // ip address of your ping target
Inet4Address IP_ORIGIN; // your own ip address
MacAddress MAC_TARGET; // target or gateway mac address
MacAddress MAC_SOURCE; // your own mac address
PcapNetworkInterface PCAP4J_NETWORK_INTERFACE; // network interface used to execute the ping

如何制作 ICMP Echo 请求数据包(作为 of IcmpV4CommonPacketofIpV4Packet的有效负载EthernetPacket):

    public Packet buildPacket() {
        IcmpV4EchoPacket.Builder icmpV4Echo = new IcmpV4EchoPacket.Builder()
                .identifier(IDENTIFIER) // optional, default zero
                .sequenceNumber(SEQUENCE); // optional, default zero
        IcmpV4CommonPacket.Builder icmpV4Common = new IcmpV4CommonPacket.Builder()
                .type(IcmpV4Type.ECHO) // type is echo
                .code(IcmpV4Code.NO_CODE) // echo request doesn't need this
                .payloadBuilder(icmpV4Echo)
                .correctChecksumAtBuild(true);
        IpV4Packet.Builder ipv4Builder = new IpV4Packet.Builder()
                .correctChecksumAtBuild(true)
                .correctLengthAtBuild(true)
                .dstAddr(IP_TARGET) // IPv4 Address where tp send the request
                .payloadBuilder(icmpV4Common)
                .protocol(IpNumber.ICMPV4) // payload is ICMPV4
                .srcAddr(IP_ORIGIN) // Your own IPv4 Address
                .tos(IpV4Rfc1349Tos.newInstance((byte) 0))
                .ttl(TTL) // time to live (1-255)
                .version(IpVersion.IPV4); // IP Version is IPv4
        EthernetPacket.Builder etherBuilder = new EthernetPacket.Builder()
                .dstAddr(MAC_TARGET) // the targets mac address
                .srcAddr(MAC_SOURCE) // your own mac address
                .type(EtherType.IPV4) // payload protocl is IPv4
                .payloadBuilder(ipv4Builder)
                .paddingAtBuild(true);
        return etherBuilder.build(); // build your packet
    }

ICMP Echo 应答或超时的侦听器:

    public PacketListener buildListener() {
        return new PacketListener() {
            @Override
            public void gotPacket(Packet packet) {
                if (!(packet instanceof EthernetPacket))
                    return;
                EthernetPacket ethernetPacket = (EthernetPacket) packet;
                packet = ethernetPacket.getPayload();
                if (!(packet instanceof IpV4Packet))
                    return;
                IpV4Packet ipV4Packet = (IpV4Packet) packet;
                IpV4Header ipV4Header = ipV4Packet.getHeader();
                packet = ipV4Packet.getPayload();
                if (!(packet instanceof IcmpV4CommonPacket))
                    return;
                IcmpV4CommonPacket icmpPacket = (IcmpV4CommonPacket) packet;
                packet = icmpPacket.getPayload();
                // successful reply just measure time and done
                if (packet instanceof IcmpV4EchoReplyPacket) {
                    IcmpV4EchoReplyPacket icmpV4EchoReplyPacket = (IcmpV4EchoReplyPacket) packet;
                    IcmpV4EchoReplyHeader icmpV4EchoReplyHeader = icmpV4EchoReplyPacket.getHeader();
                    if (icmpV4EchoReplyHeader.getIdentifier() != identifier)
                        return;
                    if (icmpV4EchoReplyHeader.getSequenceNumber() != sequence)
                        return;
                    // here you got an echo reply
                    System.out.println(packet);
                    return;
                }
                // try handle time to live exceeded messages
                if (packet instanceof IcmpV4TimeExceededPacket) {
                    packet = packet.getPayload(); // original IPv4
                    if (!(packet instanceof IpV4Packet))
                        return;
                    packet = packet.getPayload(); // original ICMP common
                    if (!(packet instanceof IcmpV4CommonPacket))
                        return;
                    packet = packet.getPayload(); // original ICMP echo
                    if (!(packet instanceof IcmpV4EchoPacket))
                        return;
                    IcmpV4EchoHeader icmpV4EchoHeader = ((IcmpV4EchoPacket)packet).getHeader();
                    if (icmpV4EchoHeader.getIdentifier() != IDENTIFIER)
                        return;
                    if(icmpV4EchoHeader.getSequenceNumber() != SEQUENCE)
                        return;
                    // HERE you got an answer, that the time to live has been used up
                    System.out.println(packet);
                    return;
                }
            };
        }

将其组合在一起:

    public static void main(String[] args) throws IOException, PcapNativeException, NotOpenException, InterruptedException {
        try (PcapHandle handle = PCAP4J_NETWORK_INTERFACE.openLive(1024, PromiscuousMode.PROMISCUOUS, 1000)) {
            // set filter to only get incoming ICMP traffic
            handle.setFilter("icmp and dst host " + Pcaps.toBpfString(IP_ORIGIN), BpfCompileMode.OPTIMIZE);
            // send ARP request
            Packet p = buildPacket();
            handle.sendPacket(p);
            // wait (forever) for ARP answer
            PacketListener listener = buildListener();
            handle.loop(-1, listener);
        }
    }
于 2022-02-04T11:54:28.033 回答
0

IcmpV4EchoPacket您可以使用、IcmpV4CommonPacket、的构建器在以太网数据包上创建 ICMPv4 Echo (ping)IpV4PacketEthernetPacket通过 发送它们PcapHandle.sendPacket()。请参考org.pcap4j.sample.SendFragmentedEchopcap4j-sample 项目。

您将需要实现 ARP 以将 IP 地址解析为 MAC 地址org.pcap4j.sample.SendArpRequest,例如 pcap4j-sample 项目中的地址。

您还需要实现一项功能,以某种方式从给定的 IP 地址中找到下一跳(默认网关左右)。Pcap4J 不提供 API 来支持这种实现。(Java 不提供 API 来获取路由表...)

你可能会更好地使用java.net.InetAddress#isReachable()

于 2016-11-19T21:55:06.173 回答