All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nl.sidnlabs.pcap.decoder.ICMPDecoder Maven / Gradle / Ivy

There is a newer version: 0.2.24
Show newest version
/*
 * ENTRADA, a big data platform for network data analytics
 *
 * Copyright (C) 2016 SIDN [https://www.sidn.nl]
 * 
 * This file is part of ENTRADA.
 * 
 * ENTRADA is free software: you can redistribute it and/or modify it under the terms of the GNU
 * Lesser General Public License as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * 
 * ENTRADA is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with ENTRADA. If
 * not, see [ 0) {
      decode((ICMPPacket) packet, payload);
      return packet;
    }
    return Packet.NULL;
  }

  private void decode(ICMPPacket packet, byte[] packetData) {

    if (packet.getIpVersion() == IPDecoder.IP_PROTOCOL_VERSION_4) {
      // ICMPv4
      // decode hdr
      packet.setType(ICMPv4Util.decodeType(packetData));
      packet.setCode(ICMPv4Util.decodeCode(packetData));

      // get the last 4 bytes of the header, this contains info
      // for specific types, ignore this data for now.
      // byte[] restOfHdr = ICMPv4Util.extractRestOfHeader(packetData)
      // decode the icmp payload which is IP hdr and 8 bytes of IP payload
      // get layer 4 payload
      // only these ipv4 error types contain a payload with the original packet
      if (packet.getType() == PROTOCOL_ICMP_V4_DESTINATION_UNREACHABLE
          || packet.getType() == PROTOCOL_ICMP_SOURCE_QUENCHE
          || packet.getType() == PROTOCOL_ICMP_REDIRECT_MESSAGE
          || packet.getType() == PROTOCOL_ICMP_TIME_EXCEEDED
          || packet.getType() == PROTOCOL_ICMP_PARAMETER_PROBLEM) {

        decodePayload(packet, ICMPv4Util.extractPayload(packetData));
        packet.setError(true);

        if (packet.getType() == PROTOCOL_ICMP_V4_DESTINATION_UNREACHABLE
            && packet.getCode() == PROTOCOL_ICMP_V4_CODE_FRAG_NEEDED) {
          packet.setMtu(v4Mtu(packetData));
        }
      } else {
        packet.setOriginalIPPacket(Packet.NULL);
        packet.setInfo(true);
      }

    } else {
      // ICMPv6
      // decode hdr
      packet.setType(ICMPv6Util.decodeType(packetData));
      packet.setCode(ICMPv6Util.decodeCode(packetData));
      // skip the checksum and 16-32 bit range
      if (packet.getType() < PROTOCOL_ICMP_V6_OFFSET_INFO_MSG) {
        // only icmpv6 error messages ( type <128) contain original packet
        decodePayload(packet, ICMPv6Util.extractPayload(packetData));
        packet.setError(true);
      } else {
        packet.setOriginalIPPacket(Packet.NULL);
        packet.setInfo(true);
      }

      if (packet.getType() == PROTOCOL_ICMP_V6_DESTINATION_UNREACHABLE
          && packet.getCode() == PROTOCOL_ICMP_V6_CODE_FRAG_NEEDED) {
        packet.setMtu(v6Mtu(packetData));
      }
    }

    // if icmp type is echo request then see if it is a RIPE probe
    if (packet.getType() == PROTOCOL_ICMP_V4_ECHO_REQUEST
        || packet.getType() == PROTOCOL_ICMP_V4_ECHO_REPLY
        || packet.getType() == PROTOCOL_ICMP_V6_ECHO_REQUEST
        || packet.getType() == PROTOCOL_ICMP_V6_ECHO_REPLY) {

      if (isClientRipeAtlas(packetData)) {
        packet.setClientType(ECHO_CLIENT_TYPE_RIPE_ATLAS);
      } else if (isClientUnixLinux(packetData)) {
        packet.setClientType(ECHO_CLIENT_TYPE_UNIX_LINUX);
      } else if (isClientWindows(packetData)) {
        packet.setClientType(ECHO_CLIENT_TYPE_WINDOWS);
      } else if (isClientPrtg(packetData)) {
        packet.setClientType(ECHO_CLIENT_TYPE_PRTG);
      }
    }

  }

  private int v4Mtu(byte[] packetData) {
    byte[] data = new byte[2];
    System.arraycopy(packetData, PROTOCOL_ICMP_V4_OFFSET_MTU, data, 0, 2);
    return ByteBuffer.wrap(data).getShort();
  }

  private int v6Mtu(byte[] packetData) {
    byte[] data = new byte[4];
    System.arraycopy(packetData, PROTOCOL_ICMP_V6_OFFSET_MTU, data, 0, 4);
    return ByteBuffer.wrap(data).getInt();
  }

  private void decodePayload(ICMPPacket packet, byte[] icmpPayload) {

    Packet ipPacket = ipDecoder.decode(icmpPayload, 0, 0, 0);
    packet.setOriginalIPPacket(ipPacket);
    if (ipPacket == Packet.NULL) {
      // decode failed
      return;
    }

    if (ipPacket instanceof DNSPacket) {
      DNSPacket dnsPacket = (DNSPacket) ipPacket;
      if (dnsPacket.getMessageCount() == 1) {
        // // this is the number of bytes in the ICMP copy
        // // this could be truncated to 8 bytes, so get the original dns response size
        dnsPacket.getMessages().get(0).setBytes(ipPacket.getPayloadLength());
      }
    }
  }

  private boolean isClientRipeAtlas(byte[] packetData) {
    byte[] echoBytes = ICMPv4Util.extractEchoRequestPayload(packetData);
    String echoStr = new String(echoBytes);

    // atlas probes have "http://atlas.ripe.net" in their echo bytes.
    // some probe type only have a substring of this url in the payload
    return StringUtils.contains(echoStr, ECHO_CLIENT_ID_RIPE_ATLAS);

  }

  private boolean isClientUnixLinux(byte[] packetData) {
    return isClient(packetData, ECHO_CLIENT_ID_UNIX_LINUX);
  }

  private boolean isClientWindows(byte[] packetData) {
    return isClient(packetData, ECHO_CLIENT_ID_WINDOWS);
  }

  private boolean isClientPrtg(byte[] packetData) {
    return isClient(packetData, ECHO_CLIENT_ID_PRTG);
  }

  private boolean isClient(byte[] packetData, String id) {
    byte[] echoBytes = ICMPv4Util.extractEchoRequestPayload(packetData);
    String echoStr = new String(echoBytes);
    return StringUtils.contains(echoStr, id);
  }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy