Loading javasrc/net/sourceforge/jpcap/net/SCTPChunkType.java 0 → 100644 +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 javasrc/net/sourceforge/jpcap/net/SCTPFields.java 0 → 100644 +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 } javasrc/net/sourceforge/jpcap/net/SCTPPacket.java 0 → 100644 +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; } } } Loading
javasrc/net/sourceforge/jpcap/net/SCTPChunkType.java 0 → 100644 +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
javasrc/net/sourceforge/jpcap/net/SCTPFields.java 0 → 100644 +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 }
javasrc/net/sourceforge/jpcap/net/SCTPPacket.java 0 → 100644 +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; } } }