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

pcap.codec.ip.Ip6 Maven / Gradle / Ivy

/** This code is licenced under the GPL version 2. */
package pcap.codec.ip;

import java.util.Objects;
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.net.Inet6Address;
import pcap.common.util.Strings;
import pcap.common.util.Validate;

/** @author Ardika Rommy Sanjaya */
@Inclubating
public class Ip6 extends Ip {

  public static final TransportLayer IPV6_ROUTING =
      new TransportLayer((byte) 43, "Routing Header for IPv6.");
  public static final TransportLayer IPV6_FRAGMENT =
      new TransportLayer((byte) 44, "Fragment Header for IPv6.");
  public static final TransportLayer IPV6_HOPOPT =
      new TransportLayer((byte) 0, "IPv6 Hop by Hop NeighborDiscoveryOptions.");
  public static final TransportLayer IPV6_DSTOPT =
      new TransportLayer((byte) 60, "IPv6 Destination NeighborDiscoveryOptions.");
  public static final TransportLayer IPV6_AH =
      new TransportLayer((byte) 51, "IPv6 Authentication Header.");

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

  private Ip6(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(this.header.payloadType().value()).newInstance(this.payloadBuffer);
    } else {
      this.payload = null;
    }
    this.builder = builder;
  }

  public static Ip6 newPacket(Memory buffer) {
    return new Builder().build(buffer);
  }

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

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

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

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

  @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 AbstractPacketHeader {

    public static final int IPV6_HEADER_LENGTH = 40;

    private final byte trafficClass;
    private final int flowLabel;
    private final short payloadLength;
    private final TransportLayer nextHeader;
    private final byte hopLimit;
    private final Inet6Address sourceAddress;
    private final Inet6Address destinationAddress;

    private final Builder builder;

    protected Header(final Builder builder) {
      super((byte) 0x06);
      this.trafficClass = builder.trafficClass;
      this.flowLabel = builder.flowLabel;
      this.payloadLength = builder.payloadLength;
      this.nextHeader = builder.nextHeader;
      this.hopLimit = builder.hopLimit;
      this.sourceAddress = builder.sourceAddress;
      this.destinationAddress = builder.destinationAddress;
      this.buffer = resetIndex(builder.buffer, length());
      this.builder = builder;
    }

    /**
     * Traffic class.
     *
     * @return returns traffic class.
     */
    public int trafficClass() {
      return trafficClass & 0xff;
    }

    /**
     * Flow label.
     *
     * @return returns flow label.
     */
    public int flowLabel() {
      return flowLabel & 0xfffff;
    }

    /**
     * Payload length.
     *
     * @return returns payload length.
     */
    public int payloadLength() {
      return payloadLength & 0xffff;
    }

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

    /**
     * Hop limit.
     *
     * @return returns hop limit.
     */
    public int hopLimit() {
      return hopLimit & 0xff;
    }

    /**
     * Source address.
     *
     * @return source address.
     */
    public Inet6Address sourceAddress() {
      return sourceAddress;
    }

    /**
     * Destination address.
     *
     * @return destination address.
     */
    public Inet6Address destinationAddress() {
      return destinationAddress;
    }

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

    @Override
    public int length() {
      return IPV6_HEADER_LENGTH;
    }

    @Override
    public Memory buffer() {
      if (buffer == null) {
        buffer = ALLOCATOR.allocate(length());
        buffer.writeInt(
            (super.version & 0xf) << 28 | (trafficClass & 0xff) << 20 | flowLabel & 0xfffff);
        buffer.writeShort(payloadLength);
        buffer.writeByte(nextHeader.value());
        buffer.writeByte(hopLimit);
        buffer.writeBytes(sourceAddress.address());
        buffer.writeBytes(destinationAddress.address());
      }
      return buffer;
    }

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

    @Override
    public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;
      Header header = (Header) o;
      return trafficClass == header.trafficClass
          && flowLabel == header.flowLabel
          && payloadLength == header.payloadLength
          && hopLimit == header.hopLimit
          && nextHeader.equals(header.nextHeader)
          && sourceAddress.equals(header.sourceAddress)
          && destinationAddress.equals(header.destinationAddress);
    }

    @Override
    public int hashCode() {
      return Objects.hash(
          trafficClass,
          flowLabel,
          payloadLength,
          nextHeader,
          hopLimit,
          sourceAddress,
          destinationAddress);
    }

    @Override
    public String toString() {
      return Strings.toStringBuilder(this)
          .add("version", version)
          .add("trafficClass", trafficClass & 0xFF)
          .add("flowLabel", flowLabel)
          .add("payloadLength", payloadLength)
          .add("nextHeader", nextHeader)
          .add("hopLimit", hopLimit)
          .add("sourceAddress", sourceAddress)
          .add("destinationAddress", destinationAddress)
          .toString();
    }
  }

  public static final class Builder extends AbstractPaketBuilder {

    static {
      TransportLayer.register(IPV6_AH, new Authentication.Builder());
      TransportLayer.register(IPV6_DSTOPT, new DestinationOptions.Builder());
      TransportLayer.register(IPV6_FRAGMENT, new Fragment.Builder());
      TransportLayer.register(IPV6_HOPOPT, new HopByHopOptions.Builder());
      TransportLayer.register(IPV6_ROUTING, new Routing.Builder());
    }

    private byte trafficClass;
    private int flowLabel;
    private short payloadLength;
    private TransportLayer nextHeader;
    private byte hopLimit;
    private Inet6Address sourceAddress;
    private Inet6Address destinationAddress;
    private Memory buffer;
    private Memory payloadBuffer;

    public Builder() {
      this.nextHeader = TransportLayer.TCP;
      this.sourceAddress = Inet6Address.ZERO;
      this.destinationAddress = Inet6Address.ZERO;
    }

    /**
     * Traffic class.
     *
     * @param trafficClass traffic class.
     * @return returns this {@link Builder}.
     */
    public Builder trafficClass(final int trafficClass) {
      this.trafficClass = (byte) (trafficClass & 0xff);
      return this;
    }

    /**
     * Flow label.
     *
     * @param flowLabel flow label.
     * @return returns this {@link Builder}.
     */
    public Builder flowLabel(final int flowLabel) {
      this.flowLabel = flowLabel & 0xfffff;
      return this;
    }

    /**
     * Payload length.
     *
     * @param payloadLength payload length.
     * @return returns this {@link Builder}.
     */
    public Builder payloadLength(final int payloadLength) {
      this.payloadLength = (short) (payloadLength & 0xffff);
      return this;
    }

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

    /**
     * Hop limit.
     *
     * @param hopLimit hop limit.
     * @return return this {@link Builder}.
     */
    public Builder hopLimit(final int hopLimit) {
      this.hopLimit = (byte) (hopLimit & 0xff);
      return this;
    }

    /**
     * Source address.
     *
     * @param sourceAddress source address.
     * @return returns this {@link Builder}.
     */
    public Builder sourceAddress(final Inet6Address sourceAddress) {
      this.sourceAddress = sourceAddress;
      return this;
    }

    /**
     * Destination address.
     *
     * @param destinationAddress destination address.
     * @return returns this {@link Builder}.
     */
    public Builder destinationAddress(final Inet6Address destinationAddress) {
      this.destinationAddress = destinationAddress;
      return this;
    }

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

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

    @Override
    public Ip6 build(final Memory buffer) {
      resetIndex(buffer);
      int iscratch = buffer.readInt();
      this.trafficClass = (byte) (iscratch >> 20 & 0xFF);
      this.flowLabel = iscratch & 0xFFFFF;
      this.payloadLength = buffer.readShort();
      this.nextHeader = TransportLayer.valueOf(buffer.readByte());
      this.hopLimit = buffer.readByte();
      byte[] addrBuf = new byte[Inet6Address.IPV6_ADDRESS_LENGTH];
      buffer.readBytes(addrBuf);
      this.sourceAddress = Inet6Address.valueOf(addrBuf);
      addrBuf = new byte[Inet6Address.IPV6_ADDRESS_LENGTH];
      buffer.readBytes(addrBuf);
      this.destinationAddress = Inet6Address.valueOf(addrBuf);
      this.buffer = buffer;
      this.payloadBuffer = buffer.slice();
      return new Ip6(this);
    }

    @Override
    public Builder reset() {
      return reset(readerIndex, Header.IPV6_HEADER_LENGTH);
    }

    @Override
    public Builder reset(int offset, int length) {
      if (buffer != null) {
        Validate.notIllegalArgument(offset + length <= buffer.capacity());
        Validate.notIllegalArgument((trafficClass & 0xFF) >= 0, ILLEGAL_HEADER_EXCEPTION);
        Validate.notIllegalArgument((flowLabel & 0xFFFFF) >= 0, ILLEGAL_HEADER_EXCEPTION);
        Validate.notIllegalArgument((payloadLength & 0xFFFF) >= 0, ILLEGAL_HEADER_EXCEPTION);
        Validate.notIllegalArgument(nextHeader != null, ILLEGAL_HEADER_EXCEPTION);
        Validate.notIllegalArgument((hopLimit & 0xFF) >= 0, ILLEGAL_HEADER_EXCEPTION);
        Validate.notIllegalArgument(sourceAddress != null, ILLEGAL_HEADER_EXCEPTION);
        Validate.notIllegalArgument(destinationAddress != null, ILLEGAL_HEADER_EXCEPTION);
        int index = offset;
        buffer.setInt(index, (6 & 0xF) << 28 | (trafficClass & 0xFF) << 20 | flowLabel & 0xFFFFF);
        index += 4;
        buffer.setShort(index, payloadLength);
        index += 2;
        buffer.setByte(index, nextHeader.value());
        index += 1;
        buffer.setByte(index, hopLimit);
        index += 1;
        buffer.setBytes(index, sourceAddress.address());
        index += Inet6Address.IPV6_ADDRESS_LENGTH;
        buffer.setBytes(index, destinationAddress.address());
      }
      return this;
    }
  }

  public abstract static class ExtensionHeader extends AbstractPacket.Header {}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy