Commit 42f40090 authored by juvancic's avatar juvancic
Browse files

updated TA

parent 5d60b8a8
Loading
Loading
Loading
Loading
+168 −0
Original line number Diff line number Diff line
// $Id: SCTPChunkType.java,v 1.00 2021/01/10 $

/***************************************************************************
 *                                                                         *
 ***************************************************************************/
package net.sourceforge.jpcap.net;

import java.util.HashMap;
import java.util.Map;

/**
 * SCTP Chunk Type
 *
 * @see <a href="https://tools.ietf.org/html/rfc4960#section-3.2">RFC 4960</a>
 * @author 
 * @since 
 */
public final class SCTPChunkType extends NamedNumber<Byte, SCTPChunkType> {

  /** */
  static final long serialVersionUID = -5598298520049931819L;

  /** Payload Data: 0 */
  public static final SCTPChunkType DATA = new SCTPChunkType((byte) 0, "Payload Data");

  /** Initiation: 1 */
  public static final SCTPChunkType INIT = new SCTPChunkType((byte) 1, "Initiation");

  /** Initiation Acknowledgement: 2 */
  public static final SCTPChunkType INIT_ACK = new SCTPChunkType((byte) 2, "Initiation Acknowledgement");

  /** Selective Acknowledgement: 3 */
  public static final SCTPChunkType SACK = new SCTPChunkType((byte) 3, "Selective Acknowledgement");

  /** Heartbeat Request: 4 */
  public static final SCTPChunkType HEARTBEAT = new SCTPChunkType((byte) 4, "Heartbeat Request");

  /** Heartbeat Acknowledgement: 5 */
  public static final SCTPChunkType HEARTBEAT_ACK = new SCTPChunkType((byte) 5, "Heartbeat Acknowledgement");

  /** Abort: 6 */
  public static final SCTPChunkType ABORT = new SCTPChunkType((byte) 6, "Abort");

  /** Shutdown: 7 */
  public static final SCTPChunkType SHUTDOWN = new SCTPChunkType((byte) 7, "Shutdown");

  /** Shutdown Acknowledgement: 8 */
  public static final SCTPChunkType SHUTDOWN_ACK = new SCTPChunkType((byte) 8, "Shutdown Acknowledgement");

  /** Operation Error: 9 */
  public static final SCTPChunkType ERROR = new SCTPChunkType((byte) 9, "Operation Error");

  /** State Cookie: 10 */
  public static final SCTPChunkType COOKIE_ECHO = new SCTPChunkType((byte) 10, "State Cookie");

  /** Cookie Acknowledgement: 11 */
  public static final SCTPChunkType COOKIE_ACK = new SCTPChunkType((byte) 11, "Cookie Acknowledgement");

  /** Explicit Congestion Notification Echo: 12 */
  public static final SCTPChunkType ECNE = new SCTPChunkType((byte) 12, "Explicit Congestion Notification Echo");

  /** Congestion Window Reduced: 13 */
  public static final SCTPChunkType CWR = new SCTPChunkType((byte) 13, "Congestion Window Reduced");

  /** Shutdown Complete: 14 */
  public static final SCTPChunkType SHUTDOWN_COMPLETE = new SCTPChunkType((byte) 14, "Shutdown Complete");

  private static final Map<Byte, SCTPChunkType> registry = new HashMap<Byte, SCTPChunkType>();

  static {
    registry.put(DATA.value(), DATA);
    registry.put(INIT.value(), INIT);
    registry.put(INIT_ACK.value(), INIT_ACK);
    registry.put(SACK.value(), SACK);
    registry.put(HEARTBEAT.value(), HEARTBEAT);
    registry.put(HEARTBEAT_ACK.value(), HEARTBEAT_ACK);
    registry.put(ABORT.value(), ABORT);
    registry.put(SHUTDOWN.value(), SHUTDOWN);
    registry.put(SHUTDOWN_ACK.value(), SHUTDOWN_ACK);
    registry.put(ERROR.value(), ERROR);
    registry.put(COOKIE_ECHO.value(), COOKIE_ECHO);
    registry.put(COOKIE_ACK.value(), COOKIE_ACK);
    registry.put(ECNE.value(), ECNE);
    registry.put(CWR.value(), CWR);
    registry.put(SHUTDOWN_COMPLETE.value(), SHUTDOWN_COMPLETE);
  }

  /** @return an ActionForUnkownType object. */
  public ActionForUnkownType getActionForUnkownType() {
    int val = (value() >> 6) & 0x03;
    return ActionForUnkownType.values()[val];
  }

  /**
   * @param value value
   * @param name name
   */
  public SCTPChunkType(Byte value, String name) {
    super(value, name);
  }

  /**
   * @param value value
   * @return a SCTPChunkType object.
   */
  public static SCTPChunkType getInstance(Byte value) {
    if (registry.containsKey(value)) {
      return registry.get(value);
    } else {
      return new SCTPChunkType(value, "unknown");
    }
  }

  /**
   * @param type type
   * @return a SCTPChunkType object.
   */
  public static SCTPChunkType register(SCTPChunkType type) {
    return registry.put(type.value(), type);
  }

  /** @return the value of this object as an int. */
  public int valueAsInt() {
    return 0xFF & value();
  }

  /** @return a string representation of this value. */
  @Override
  public String valueAsString() {
    return String.valueOf(valueAsInt());
  }

  @Override
  public int compareTo(SCTPChunkType o) {
    return value().compareTo(o.value());
  }

  /**
   * Action that must be taken if the processing endpoint does not recognize the Chunk Type.
   * (highest-order 2 bits of the Chunk Type)
   *
   * @see <a href="https://tools.ietf.org/html/rfc4960#section-3.2">RFC 4960</a>
   * @author Kaito Yamada
   * @since pcap4j 1.6.6
   */
  public static enum ActionForUnkownType {

    /**
     * Stop processing this SCTP packet and discard it, do not process any further chunks within it.
     */
    DISCARD,

    /**
     * Stop processing this SCTP packet and discard it, do not process any further chunks within it,
     * and report the unrecognized chunk in an 'Unrecognized Chunk Type'.
     */
    DISCARD_AND_REPORT,

    /** Skip this chunk and continue processing. */
    SKIP,

    /**
     * Skip this chunk and continue processing, but report in an ERROR chunk using the 'Unrecognized
     * Chunk Type' cause of error.
     */
    SKIP_AND_REPORT,
  }
}
 No newline at end of file
+97 −0
Original line number Diff line number Diff line
// $Id: SCTPFields.java,v 1.00 2021/01/10 $

/***************************************************************************
 *                                                                         *
 ***************************************************************************/
package net.sourceforge.jpcap.net;


/**
 * SCTP protocol field encoding information.
 *
 * @author 
 * @version 
 * @lastModifiedBy 
 * @lastModifiedAt $Date: 2021/01/25 $
 */
public interface SCTPFields
{
  
	/**
	   * SCTP header
	   *
	   * <pre style="white-space: pre;">
	   *  0                              16                            31
	   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	   * |           Src Port            |           Dst Port            |
	   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	   * |                        Verification Tag                       |
	   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	   * |                            Checksum                           |
	   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	   * |                          Chunk #1                             |
	   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	   * |                           ...                                 |
	   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	   * |                          Chunk #n                             |
	   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	   * </pre>
	   *
	   * @see <a href="https://tools.ietf.org/html/rfc4960">RFC 4960</a>
	   */
	    int SRC_PORT_OFFSET = 0;
	    int SRC_PORT_SIZE = 2;
	    int DST_PORT_OFFSET = SRC_PORT_OFFSET + SRC_PORT_SIZE;
	    int DST_PORT_SIZE = 2;
	    int VERIFICATION_TAG_OFFSET = DST_PORT_OFFSET + DST_PORT_SIZE;
	    int VERIFICATION_TAG_SIZE = 4;
	    int CHECKSUM_OFFSET = VERIFICATION_TAG_OFFSET + VERIFICATION_TAG_SIZE;
	    int CHECKSUM_SIZE = 4;
	    int CHUNKS_OFFSET = CHECKSUM_OFFSET + CHECKSUM_SIZE;	
	    
	    
	   /** 
	    * SCTP Chunk

	        0                   1                   2                   3
	        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
	       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	       |   Chunk Type  | Chunk  Flags  |        Chunk Length           |
	       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	       \                                                               \
	       /                          Chunk Value                          /
	       \                                                               \
	       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	   **/
	    
	    int CHUNK_TYPE_OFFSET = 0;
	    int CHUNK_TYPE_SIZE = 1;
	    int CHUNK_FLAGS_OFFSET = CHUNK_TYPE_OFFSET + CHUNK_TYPE_SIZE;
	    int CHUNK_FLAGS_SIZE = 1;
	    int CHUNK_LEN_OFFSET = CHUNK_FLAGS_OFFSET + CHUNK_FLAGS_SIZE;
	    int CHUNK_LEN_SIZE = 2;
	    int CHUNK_RAWDATA_OFFSET = CHUNK_LEN_OFFSET + CHUNK_LEN_SIZE;
	    
	    /**
	     * 3.3.1 Payload Data (DATA) (0)
                 The following format MUST be used for the DATA chunk:

	        0                   1                   2                   3
	        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
	       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	       |   Type = 0    | Reserved|U|B|E|    Length                     |
	       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	       |                              TSN                              |
	       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	       |      Stream Identifier S      |   Stream Sequence Number n    |
	       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	       |                  Payload Protocol Identifier                  |
	       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	       \                                                               \
	       /                 User Data (seq n of Stream S)                 /
	       \                                                               \
	       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	     */
	    
	    int CHUNK_USERDATA_OFFSET = CHUNK_RAWDATA_OFFSET + 12; //Only USER Data from DATA chunk is interesting
}
+358 −0
Original line number Diff line number Diff line
// $Id: SCTPPacket.java,v 1.00 21/01/10 $

/***************************************************************************
 * 											                               *
 ***************************************************************************/
package net.sourceforge.jpcap.net;

import net.sourceforge.jpcap.util.AnsiEscapeSequences;
import net.sourceforge.jpcap.util.ArrayHelper;
import net.sourceforge.jpcap.util.Timeval;
import java.io.Serializable;

import java.util.ArrayList;
import java.util.List;


/**
 * A SCTP packet.
 * <p>
 * Extends an IP packet, adding a SCTP header and SCTP data payload.
 *
 * @author 
 * @version 
 * @lastModifiedBy 
 * @lastModifiedAt $Date: 2021/01/25 $
 */
public class SCTPPacket extends IPPacket implements SCTPFields, Serializable
{
    int srcPort;
    int dstPort;
    int verificationTag;
    int checksum;
    
  /** 
   * Create a new SCTP packet.
   */
  public SCTPPacket(int lLen, byte [] bytes) {
    super(lLen,bytes);
    // set SCTP header length
    _sctpHeaderLength = CHUNKS_OFFSET;

    // set data (payload) length based on info in headers (note: tcpdump
    //  can return extra junk bytes which bubble up to here
    int tmpLen = getLength() - getIpHeaderLength() - _sctpHeaderLength;
    _payloadDataLength = (tmpLen < 0) ? 0 : tmpLen;
  }

  /**
   * Create a new SCTP packet.
   */
  public SCTPPacket(int lLen, byte [] bytes, Timeval tv) {
    this(lLen, bytes);
    this._timeval = tv;
  }

  private int _sourcePort;
  private boolean _sourcePortSet = false;
  /** 
   * Fetch the port number on the source host.
   */
  public int getSourcePort() {
    if(! _sourcePortSet) {
      _sourcePort =
	ArrayHelper.extractInteger(_bytes, _ipOffset + SRC_PORT_OFFSET,	SRC_PORT_SIZE);
      _sourcePortSet = true;
    }
    return _sourcePort;
  }

  private int _destinationPort;
  private boolean _destinationPortSet = false;
  /** 
   * Fetches the port number on the destination host.
   */
  public int getDestinationPort() {
    if(! _destinationPortSet) {
      _destinationPort = 
	ArrayHelper.extractInteger(_bytes, _ipOffset + DST_PORT_OFFSET,	DST_PORT_SIZE);
      _destinationPortSet = true;
    }
    return _destinationPort;
  }

  private long _verificationtag;
  private boolean _verificationtagSet = false;
  /** 
   * Fetch the packet verification tag.
   */
  public long getVerificationTag() {
    if(! _verificationtagSet) {
    	_verificationtag =
	ArrayHelper.extractLong(_bytes, _ipOffset + VERIFICATION_TAG_OFFSET, VERIFICATION_TAG_SIZE);
      _verificationtagSet = true;
    }
    return _verificationtag;
  }

  private int _checksum;
  private boolean _checksumSet = false;
  /** 
   *    Fetch the packet acknowledgment number.
   */
  public int getSCTPChecksum() {
    if(! _checksumSet) {
    	_checksum =
	ArrayHelper.extractInteger/*extractLong*/(_bytes, _ipOffset + CHECKSUM_OFFSET,	CHECKSUM_SIZE);
    	_checksumSet = true;
    }
    return _checksum;
  }

  /**
   * Fetch the header checksum.
   */
  public int getChecksum() {
    return getSCTPChecksum();
  }

  // this gets set by the constructor
  private int _sctpHeaderLength;

  /** 
   * Fetch the SCTP header length in bytes.
   */
  public int getSCTPHeaderLength() {
    return _sctpHeaderLength;
  }

  /** 
   * Fetch the SCTP header length in bytes.
   */
  public int getSctpHeaderLength() {
    // this is the old method call, but everything else uses all caps for
    // SCTP, so in the interest of consistency...
    return getSCTPHeaderLength();
  }

  /**
   * Fetches the packet SCTP header length.
   */
  public int getHeaderLength() {
    return getSCTPHeaderLength();
  }

  // this gets set by the constructor
  private int _payloadDataLength;
  /**
   * Fetches the length of the payload data.
   */
  public int getPayloadDataLength() {
    return _payloadDataLength;
  }


  private byte[] _sctpHeaderBytes = null;
  /**
   * Fetch the SCTP header a byte array.
   */
  public byte[] getSCTPHeader() {
    if(_sctpHeaderBytes == null) {
      _sctpHeaderBytes =
	PacketEncoding.extractHeader(_ipOffset, getSctpHeaderLength(), _bytes);
    }
    return _sctpHeaderBytes;
  }

  /** 
   * Fetch the SCTP header as a byte array.
   */
  public byte[] getHeader() {
    return getSCTPHeader();
  }

  private byte[] _sctpDataBytes = null;
  /** 
   * Fetch the SCTP data as a byte array.
   */
  public byte[] getSCTPData() {
    if(_sctpDataBytes == null) {
      // set data length based on info in headers (note: tcpdump
      //  can return extra junk bytes which bubble up to here
      _sctpDataBytes =	PacketEncoding.extractData(_ipOffset, getSctpHeaderLength(), _bytes, getPayloadDataLength());
    }
    return _sctpDataBytes;
  }

  /**
   * Fetch the SCTP data as a byte array.
   */
  public byte[] getData() {
    return getSCTPData();
  }
  
  private List<SctpChunk> _chunks=null;
  /** @return chunks */
  public List<SctpChunk> getChunks() {
	
	if(_chunks == null) {
	    // set data length based on info in headers (note: tcpdump
	    //  can return extra junk bytes which bubble up to here
	    _chunks = new ArrayList<SctpChunk>();
	    int length = getPayloadDataLength();
	    int offset = 0;
	    
	      while (length != 0) {
	    	SCTPChunkType type = SCTPChunkType.getInstance(this.getData()[offset]);
	        SctpChunk newOne = new SctpChunk(this.getData(), offset, length, type);
	        
	        if (type == SCTPChunkType.DATA) {//keep only userdata chunks
	          _chunks.add(newOne);
	        }
	        
	        int newOneLen = newOne.length();
	        offset += newOneLen;
	        length -= newOneLen;
	      }    
	}    
    return new ArrayList<SctpChunk>(_chunks);
  }

  /**
   * Convert this SCTP packet to a readable string.
   */
  public String toString() {
    return toColoredString(false);
  }

  /**
   * Generate string with contents describing this SCTP packet.
   * @param colored whether or not the string should contain ansi
   * color escape sequences.
   */
  public String toColoredString(boolean colored) {
    StringBuffer buffer = new StringBuffer();
    buffer.append('[');
    if(colored) buffer.append(getColor());
    buffer.append("SCTPPacket");
    if(colored) buffer.append(AnsiEscapeSequences.RESET);
    buffer.append(": ");
    buffer.append(getSourceAddress());
    buffer.append('.');
    buffer.append(IPPort.getName(getSourcePort()));
    buffer.append(" -> ");
    buffer.append(getDestinationAddress());
    buffer.append('.');
    buffer.append(IPPort.getName(getDestinationPort()));

    buffer.append(" l=" + getSCTPHeaderLength() + "," + getPayloadDataLength());
    
    int i=0;
    while(i < getChunks().size()) {
        buffer.append(getChunks().get(i).toString());
        i++;
    }
    buffer.append(']');
    
    return buffer.toString();
  }

  /**
   * Convert this SCTP packet to a verbose.
   */
  public String toColoredVerboseString(boolean colored) {
    StringBuffer buffer = new StringBuffer();
    buffer.append('[');
    if(colored) buffer.append(getColor());
    buffer.append("SCTPPacket");
    if(colored) buffer.append(AnsiEscapeSequences.RESET);
    buffer.append(": ");
    buffer.append("sport=" + getSourcePort() + ", ");
    buffer.append("dport=" + getDestinationPort() + ", ");
    buffer.append("hlen=" + getHeaderLength() + ", ");
    
    buffer.append("wsize=" + getVerificationTag() + ", ");
    buffer.append("sum=0x" + Integer.toHexString(getChecksum()) + ", ");
    buffer.append(']');

    return buffer.toString();
  }

  /**
   * Fetch ascii escape sequence of the color associated with this packet type.
   */
  public String getColor() {
    return AnsiEscapeSequences.YELLOW;
  }

  private String _rcsid = 
    "$Id: SCTPPacket.java,v 1.00 2021/01/10 $";
  
  /**
   * The interface representing an SCTP Chunk Field. 
   * @see <a href="https://tools.ietf.org/html/rfc4960#section-3.2">RFC 4960</a>
   */
  public class SctpChunk /*extends Serializable*/ {

	SCTPChunkType _SCTPChunkType;
	int _chunkFlags;
	int _chunkLen;
	byte[] _chunkRawData;
	
	SctpChunk(byte[] _bytes, int _offset, int length, SCTPChunkType type){
		_SCTPChunkType=type;
		_chunkFlags=ArrayHelper.extractInteger(_bytes, _offset + CHUNK_FLAGS_OFFSET, CHUNK_FLAGS_SIZE);
		_chunkLen=ArrayHelper.extractInteger(_bytes, _offset + CHUNK_LEN_OFFSET, CHUNK_LEN_SIZE);
		_chunkRawData=PacketEncoding.extractData(_offset, CHUNK_RAWDATA_OFFSET, _bytes, length()-CHUNK_RAWDATA_OFFSET);
		if (_SCTPChunkType == SCTPChunkType.DATA) {//keep only userdata
			_chunkRawData=PacketEncoding.extractData(_offset, CHUNK_USERDATA_OFFSET, _bytes, length()-CHUNK_USERDATA_OFFSET);
		}
	}
    
	/** @return type */
    public SCTPChunkType getType() {
        return _SCTPChunkType;	
    }

    /** @return length */
    public int length() {
    	return _chunkLen;
    }

    /** @return raw data */
    public byte[] getRawData() {
    	return _chunkRawData;
    }

    /** @return user data */
    public byte[] getUserData() {
    	return _chunkRawData;
    }
    
    public String toString() {
        return toColoredString(false);
    }
    
    public String toColoredString(boolean colored) {
        StringBuffer buffer = new StringBuffer();
        buffer.append('[');
        if(colored) buffer.append(getColor());
        buffer.append("SCTP Chunk");
        if(colored) buffer.append(AnsiEscapeSequences.RESET);
        buffer.append(": ");
        buffer.append(getType().toString());
        buffer.append(':');
        buffer.append(" l=" + length() );
        buffer.append(']');
        
        return buffer.toString();
      }
    
    public String getColor() {
        return AnsiEscapeSequences.YELLOW;
      }
  }
  
}