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

pcap.codec.ip.ip6.Routing Maven / Gradle / Ivy

There is a newer version: 1.5.1
Show newest version
/** This code is licenced under the GPL version 2. */
package pcap.codec.ip.ip6;

import java.util.HashMap;
import java.util.Map;
import pcap.codec.AbstractPacket;
import pcap.codec.Packet;
import pcap.codec.TransportLayer;
import pcap.codec.ip.Ip6;
import pcap.common.annotation.Inclubating;
import pcap.common.memory.Memory;
import pcap.common.util.NamedNumber;
import pcap.common.util.Strings;
import pcap.common.util.Validate;

/** @author Ardika Rommy Sanjaya */
@Inclubating
public class Routing extends AbstractPacket {

  private final Header header;
  private final Packet payload;
  private final Builder builder;

  private Routing(final Builder builder) {
    this.header = new Header(builder);
    this.payloadBuffer = builder.payloadBuffer;
    if (this.payloadBuffer != null
        && this.payloadBuffer.readerIndex() < this.payloadBuffer.writerIndex()) {
      this.payload =
          TransportLayer.valueOf(header.payloadType().value()).newInstance(this.payloadBuffer);
    } else {
      this.payload = null;
    }
    this.builder = builder;
  }

  @Override
  public Header header() {
    return header;
  }

  @Override
  public Packet payload() {
    return payload;
  }

  @Override
  public Builder builder() {
    return builder;
  }

  @Override
  public Memory buffer() {
    return header().buffer();
  }

  @Override
  public String toString() {
    return Strings.toStringBuilder(this)
        .add("header", header)
        .add("payload", payload != null ? payload.getClass().getSimpleName() : "(None)")
        .toString();
  }

  public static final class Header extends Ip6.ExtensionHeader {

    public static final int FIXED_ROUTING_HEADER_LENGTH = 4;
    public static final int FIXED_ROUTING_DATA_LENGTH = 4;

    private final TransportLayer nextHeader;
    private final byte extensionLength;
    private final Type routingType;
    private final byte segmentLeft;

    private final byte[] routingData;

    private final Builder builder;

    private Header(final Builder builder) {
      this.nextHeader = builder.nextHeader;
      this.extensionLength = builder.extensionLength;
      this.routingType = builder.routingType;
      this.segmentLeft = builder.segmentLeft;
      this.routingData = builder.routingData;
      this.buffer = resetIndex(builder.buffer, length());
      this.builder = builder;
    }

    /**
     * Next protocol type.
     *
     * @return returns {@link TransportLayer}.
     */
    public TransportLayer nextHeader() {
      return nextHeader;
    }

    /**
     * Extension length.
     *
     * @return returns extension length.
     */
    public int extensionLength() {
      return extensionLength & 0xff;
    }

    /**
     * Routing type.
     *
     * @return returns {@link Type}.
     */
    public Type routingType() {
      return routingType;
    }

    /**
     * Segment left.
     *
     * @return returns segment left.
     */
    public int segmentLeft() {
      return segmentLeft & 0xff;
    }

    /**
     * Routing data.
     *
     * @return returns routing data.
     */
    public byte[] routingData() {
      byte[] routingData = new byte[this.routingData.length];
      System.arraycopy(this.routingData, 0, routingData, 0, routingData.length);
      return routingData;
    }

    @Override
    public TransportLayer payloadType() {
      return nextHeader;
    }

    @Override
    public int length() {
      return FIXED_ROUTING_HEADER_LENGTH + (routingData == null ? 0 : routingData.length);
    }

    @Override
    public Memory buffer() {
      if (buffer == null) {
        buffer = ALLOCATOR.allocate(length());
        buffer.writeByte(nextHeader.value());
        buffer.writeByte(extensionLength);
        buffer.writeByte(routingType.value());
        buffer.writeByte(segmentLeft);
        if (routingData != null) {
          buffer.writeBytes(routingData);
        }
      }
      return buffer;
    }

    @Override
    public String toString() {
      return Strings.toStringBuilder(this)
          .add("nextHeader", nextHeader)
          .add("extensionLength", extensionLength)
          .add("routingType", routingType)
          .add("segmentLeft", segmentLeft)
          .add("routingData", Strings.hex(routingData))
          .toString();
    }

    @Override
    public Builder builder() {
      return builder;
    }
  }

  public static final class Builder extends AbstractPacket.Builder {

    private TransportLayer nextHeader;
    private byte extensionLength;
    private Type routingType;
    private byte segmentLeft;

    private byte[] routingData;

    private Memory buffer;
    private Memory payloadBuffer;

    /**
     * Next protocol type.
     *
     * @param nextHeader next protocol type.
     * @return returns this {@link Builder}.
     */
    public Builder nextHeader(final TransportLayer nextHeader) {
      this.nextHeader = nextHeader;
      return this;
    }

    /**
     * Extension length.
     *
     * @param extensionLength extension length.
     * @return returns this {@link Builder}.
     */
    public Builder extensionLength(final int extensionLength) {
      this.extensionLength = (byte) (extensionLength & 0xff);
      return this;
    }

    /**
     * Routing type.
     *
     * @param routingType routing type.
     * @return returns this {@link Builder}.
     */
    public Builder routingType(final Type routingType) {
      this.routingType = routingType;
      return this;
    }

    /**
     * Segment left.
     *
     * @param segmentLeft segment left.
     * @return returns this {@link Builder}.
     */
    public Builder segmentLeft(final int segmentLeft) {
      this.segmentLeft = (byte) (segmentLeft & 0xff);
      return this;
    }

    /**
     * Add routing data.
     *
     * @param routingData routing data.
     * @return returns this {@link Builder} object.
     */
    public Builder routingData(final byte[] routingData) {
      this.routingData = new byte[routingData.length];
      System.arraycopy(routingData, 0, this.routingData, 0, this.routingData.length);
      return this;
    }

    @Override
    public Builder payload(AbstractPacket packet) {
      this.payloadBuffer = packet.buffer();
      return this;
    }

    @Override
    public Routing build() {
      return new Routing(this);
    }

    @Override
    public Routing build(final Memory buffer) {
      resetIndex(buffer);
      this.nextHeader = TransportLayer.valueOf(buffer.readByte());
      this.extensionLength = buffer.readByte();
      this.routingType = Type.valueOf(buffer.readByte());
      this.segmentLeft = buffer.readByte();
      this.routingData = new byte[Header.FIXED_ROUTING_DATA_LENGTH + 8 * this.extensionLength];
      buffer.readBytes(this.routingData);
      this.buffer = buffer;
      this.payloadBuffer = buffer.slice();
      return new Routing(this);
    }

    @Override
    public Builder reset() {
      return reset(readerIndex, Header.FIXED_ROUTING_HEADER_LENGTH + routingData.length);
    }

    @Override
    public Builder reset(int offset, int length) {
      if (buffer != null) {
        Validate.notIllegalArgument(offset + length <= buffer.capacity());
        Validate.notIllegalArgument(nextHeader != null, ILLEGAL_HEADER_EXCEPTION);
        Validate.notIllegalArgument(extensionLength >= 0, ILLEGAL_HEADER_EXCEPTION);
        Validate.notIllegalArgument(routingType != null, ILLEGAL_HEADER_EXCEPTION);
        Validate.notIllegalArgument(segmentLeft >= 0, ILLEGAL_HEADER_EXCEPTION);
        Validate.notIllegalArgument(routingData != null, ILLEGAL_HEADER_EXCEPTION);
        int index = offset;
        buffer.setByte(index, nextHeader.value());
        index += 1;
        buffer.setByte(index, extensionLength);
        index += 1;
        buffer.setByte(index, routingType.value());
        index += 1;
        buffer.setByte(index, segmentLeft);
        index += 1;
        buffer.setBytes(index, routingData);
      }
      return this;
    }
  }

  public static final class Type extends NamedNumber {

    public static final Type UNKNOWN = new Type((byte) -1, "UNKNOWN.");

    public static final Type DEPRECATED_01 =
        new Type(
            (byte) 0,
            "Due to the fact that with Routing HeaderAbstract type 0 a simple but effective[15]"
                + " denial-of-service attack could be launched, this header is deprecated since 2007[16]"
                + " and host and routers are required to ignore these headers.");

    public static final Type DEPRECATED_02 =
        new Type(
            (byte) 1,
            "Used for the Nimrod[17] project funded by DARPA. It is deprecated since 2009.");

    public static final Type ALLOWED_01 =
        new Type(
            (byte) 2,
            "A limited version of type 0 and is used for Mobile IPv6, where it can hold the Home Address of the Mobile Node.");

    public static final Type ALLOWED_02 =
        new Type((byte) 3, "RPL Source Route HeaderAbstract[18] for Low-Power and Lossy Networks.");

    public static final Type PRIVATE_USE_01 =
        new Type(
            (byte) 253,
            "May be used for testing, not for actual implementations. RFC3692-style Experiment 1.[13]");

    public static final Type PRIVATE_USE_02 =
        new Type(
            (byte) 254,
            "May be used for testing, not for actual implementations. RFC3692-style Experiment 2.[13]");

    private static final Map REGISTRY = new HashMap<>();

    static {
      REGISTRY.put(DEPRECATED_01.value(), DEPRECATED_01);
      REGISTRY.put(DEPRECATED_02.value(), DEPRECATED_02);
      REGISTRY.put(ALLOWED_01.value(), ALLOWED_01);
      REGISTRY.put(ALLOWED_02.value(), ALLOWED_02);
      REGISTRY.put(PRIVATE_USE_01.value(), PRIVATE_USE_01);
      REGISTRY.put(PRIVATE_USE_02.value(), PRIVATE_USE_02);
    }

    protected Type(Byte value, String name) {
      super(value, name);
    }

    /**
     * Get routing type from value.
     *
     * @param value value.
     * @return returns {@link Type}.
     */
    public static Type valueOf(final byte value) {
      Type type = REGISTRY.get(value);
      if (type == null) {
        return UNKNOWN;
      }
      return type;
    }

    /**
     * Add new routing type to registry.
     *
     * @param type routing type.
     * @return returns {@link Type}.
     */
    public static Type register(final Type type) {
      REGISTRY.put(type.value(), type);
      return type;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy