1 /*******************************************************************************
2 * Copyright (c) 2014 Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Vincent Perot - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.internal
.pcap
.core
.protocol
.tcp
;
15 import java
.nio
.ByteBuffer
;
16 import java
.nio
.ByteOrder
;
17 import java
.util
.Arrays
;
20 import org
.eclipse
.jdt
.annotation
.NonNull
;
21 import org
.eclipse
.jdt
.annotation
.Nullable
;
22 import org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
;
23 import org
.eclipse
.tracecompass
.internal
.pcap
.core
.packet
.BadPacketException
;
24 import org
.eclipse
.tracecompass
.internal
.pcap
.core
.packet
.Packet
;
25 import org
.eclipse
.tracecompass
.internal
.pcap
.core
.protocol
.PcapProtocol
;
26 import org
.eclipse
.tracecompass
.internal
.pcap
.core
.protocol
.unknown
.UnknownPacket
;
27 import org
.eclipse
.tracecompass
.internal
.pcap
.core
.trace
.PcapFile
;
28 import org
.eclipse
.tracecompass
.internal
.pcap
.core
.util
.ConversionHelper
;
30 import com
.google
.common
.collect
.ImmutableMap
;
31 import com
.google
.common
.collect
.ImmutableMap
.Builder
;
34 * Class that represents a TCP packet.
36 * @author Vincent Perot
38 public class TCPPacket
extends Packet
{
40 private final @Nullable Packet fChildPacket
;
41 private final @Nullable ByteBuffer fPayload
;
43 private final int fSourcePort
;
44 private final int fDestinationPort
;
45 private final long fSequenceNumber
;
46 private final long fAcknowledgmentNumber
;
47 private final int fDataOffset
; // in 4 bytes block
48 private final byte fReservedField
;
49 private final boolean fNSFlag
;
50 private final boolean fCWRFlag
;
51 private final boolean fECEFlag
;
52 private final boolean fURGFlag
;
53 private final boolean fACKFlag
;
54 private final boolean fPSHFlag
;
55 private final boolean fRSTFlag
;
56 private final boolean fSYNFlag
;
57 private final boolean fFINFlag
;
58 private final int fWindowSize
;
59 private final int fChecksum
;
60 private final int fUrgentPointer
;
61 private final byte @Nullable [] fOptions
; // TODO Interpret options.
63 private @Nullable TCPEndpoint fSourceEndpoint
;
64 private @Nullable TCPEndpoint fDestinationEndpoint
;
66 private @Nullable Map
<String
, String
> fFields
;
69 * Constructor of the TCP Packet class.
72 * The file that contains this packet.
74 * The parent packet of this packet (the encapsulating packet).
76 * The entire packet (header and payload).
77 * @throws BadPacketException
78 * Thrown when the packet is erroneous.
80 public TCPPacket(PcapFile file
, @Nullable Packet parent
, ByteBuffer packet
) throws BadPacketException
{
81 super(file
, parent
, PcapProtocol
.TCP
);
83 // The endpoints are lazy loaded. They are defined in the get*Endpoint()
85 fSourceEndpoint
= null;
86 fDestinationEndpoint
= null;
90 packet
.order(ByteOrder
.BIG_ENDIAN
);
93 fSourcePort
= ConversionHelper
.unsignedShortToInt(packet
.getShort());
94 fDestinationPort
= ConversionHelper
.unsignedShortToInt(packet
.getShort());
95 fSequenceNumber
= ConversionHelper
.unsignedIntToLong(packet
.getInt());
96 fAcknowledgmentNumber
= ConversionHelper
.unsignedIntToLong(packet
.getInt());
98 byte storage
= packet
.get();
99 fDataOffset
= ((storage
& 0b11110000
) >>> 4) & 0x000000FF;
100 fReservedField
= (byte) ((storage
& 0b00001110
) >>> 1);
101 fNSFlag
= isBitSet(storage
, 0);
103 storage
= packet
.get();
104 fCWRFlag
= isBitSet(storage
, 7);
105 fECEFlag
= isBitSet(storage
, 6);
106 fURGFlag
= isBitSet(storage
, 5);
107 fACKFlag
= isBitSet(storage
, 4);
108 fPSHFlag
= isBitSet(storage
, 3);
109 fRSTFlag
= isBitSet(storage
, 2);
110 fSYNFlag
= isBitSet(storage
, 1);
111 fFINFlag
= isBitSet(storage
, 0);
113 fWindowSize
= ConversionHelper
.unsignedShortToInt(packet
.getShort());
114 fChecksum
= ConversionHelper
.unsignedShortToInt(packet
.getShort());
115 fUrgentPointer
= ConversionHelper
.unsignedShortToInt(packet
.getShort());
117 // Get options if any
118 if (fDataOffset
> TCPValues
.DEFAULT_HEADER_LENGTH
) {
119 fOptions
= new byte[(fDataOffset
- TCPValues
.DEFAULT_HEADER_LENGTH
) * TCPValues
.BLOCK_SIZE
];
120 packet
.get(fOptions
);
125 // Get payload if any.
126 if (packet
.array().length
- packet
.position() > 0) {
127 byte[] array
= new byte[packet
.array().length
- packet
.position()];
129 ByteBuffer payload
= ByteBuffer
.wrap(array
);
130 payload
.order(ByteOrder
.BIG_ENDIAN
);
138 fChildPacket
= findChildPacket();
143 public @Nullable Packet
getChildPacket() {
148 public @Nullable ByteBuffer
getPayload() {
155 * See http://www.iana.org/assignments/service-names-port-numbers/service-
156 * names-port-numbers.xhtml or
157 * http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
160 protected @Nullable Packet
findChildPacket() throws BadPacketException
{
161 // TODO implement further protocols and update this
162 ByteBuffer payload
= fPayload
;
163 if (payload
== null) {
167 return new UnknownPacket(getPcapFile(), this, payload
);
171 public String
toString() {
172 final ByteBuffer payload
= fPayload
;
174 if (payload
!= null) {
175 length
= payload
.array().length
;
178 String flagString
= ""; // TODO Finish it. Im just too lazy. //$NON-NLS-1$
179 String string
= getProtocol().getName() + ", Source Port: " + fSourcePort
+ ", Destination Port: " + fDestinationPort
+ //$NON-NLS-1$ //$NON-NLS-2$
180 "\nSequence Number: " + fSequenceNumber
+ ", Acknowledgment Number: " + fAcknowledgmentNumber
+ //$NON-NLS-1$ //$NON-NLS-2$
181 "\nHeader length: " + fDataOffset
* TCPValues
.BLOCK_SIZE
+ " bytes, Data length: " + length
+ //$NON-NLS-1$ //$NON-NLS-2$
182 "\n" + flagString
+ "Window size value: " + fWindowSize
+ ", Urgent Pointer: " + String
.format("%s%04x", "0x", fUrgentPointer
) + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
183 "\nChecksum: " + String
.format("%s%04x", "0x", fChecksum
) + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
184 final Packet child
= fChildPacket
;
186 return string
+ child
.toString();
192 * Getter method that returns the TCP Source Port.
194 * @return The source Port.
196 public int getSourcePort() {
201 * Getter method that returns the TCP Destination Port.
203 * @return The destination Port.
205 public int getDestinationPort() {
206 return fDestinationPort
;
210 * Getter method that returns the Sequence Number. The sequence number has a
213 * <li>If the SYN flag is set (1), then this is the initial sequence number.
214 * The sequence number of the actual first data byte and the acknowledged
215 * number in the corresponding ACK are then this sequence number plus 1.</li>
216 * <li>If the SYN flag is clear (0), then this is the accumulated sequence
217 * number of the first data byte of this segment for the current session.</li>
220 * Source: http://en.wikipedia.org/wiki/Transmission_Control_Protocol
222 * @return The Sequence Number.
224 public long getSequenceNumber() {
225 return fSequenceNumber
;
229 * Getter method that returns the Acknowledgment Number.
231 * If the ACK flag is set then the value of this field is the next sequence
232 * number that the receiver is expecting. This acknowledges receipt of all
233 * prior bytes (if any). The first ACK sent by each end acknowledges the
234 * other end's initial sequence number itself, but no data.
236 * Source: http://en.wikipedia.org/wiki/Transmission_Control_Protocol
238 * @return The Acknowledgment Number.
240 public long getAcknowledgmentNumber() {
241 return fAcknowledgmentNumber
;
245 * Getter method that returns the size of the TCP header in 4 bytes data
246 * block. The minimum size is 5 words and the maximum is 15 words.
248 * @return The Data Offset.
250 public int getDataOffset() {
255 * Getter method that returns the Reserved field. This field is for future
256 * use and should always be zero. In this library, it is used as a mean to
257 * verify the validity of a TCP packet.
259 * @return The Reserved Field.
261 public byte getReservedField() {
262 return fReservedField
;
266 * Getter method that returns the state of the NS flag.
268 * @return The state of the NS flag.
270 public boolean isNSFlagSet() {
275 * Getter method that returns the state of the CWR flag.
277 * @return The state of the CWR flag.
279 public boolean isCongestionWindowReducedFlagSet() {
284 * Getter method that returns the state of the ECE flag.
286 * @return The state of the ECE flag.
288 public boolean isECNEchoFlagSet() {
293 * Getter method that returns the state of the URG flag.
295 * @return The state of the URG flag.
297 public boolean isUrgentFlagSet() {
302 * Getter method that returns the state of the ACK flag.
304 * @return The state of the ACK flag.
306 public boolean isAcknowledgeFlagSet() {
311 * Getter method that returns the state of the PSH flag.
313 * @return The state of the PSH flag.
315 public boolean isPushFlagSet() {
320 * Getter method that returns the state of the RST flag.
322 * @return The state of the RST flag.
324 public boolean isResetFlagSet() {
329 * Getter method that returns the state of the SYN flag.
331 * @return The state of the SYN flag.
333 public boolean isSynchronizationFlagSet() {
338 * Getter method that returns the state of the FIN flag.
340 * @return The state of the FIN flag.
342 public boolean isFinalFlagSet() {
347 * Getter method that returns the size of the windows, in windows size unit
348 * (by default, bytes), that the sender of this packet is willing to
351 * @return The Window Size.
353 public int getWindowSize() {
358 * Getter method that returns the checksum of this packet. This checksum may
359 * be wrong if the packet is erroneous.
361 * @return The data and header checksum.
363 public int getChecksum() {
368 * Getter method that returns the Urgent Pointer. If the URG flag is set,
369 * this field is an offset from the sequence number indicating the last
372 * @return The Urgent Pointer.
374 public int getUrgentPointer() {
375 return fUrgentPointer
;
379 * Getter method that returns the options. This method returns null if no
380 * options are present.
382 * @return The options of the packet.
384 public byte @Nullable [] getOptions() {
385 byte[] options
= fOptions
;
386 if (options
== null) {
389 return Arrays
.copyOf(options
, options
.length
);
393 public boolean validate() {
394 // Not yet implemented. ATM, we consider that all packets are valid.
395 // This is the case for all packets.
396 // TODO Implement it.
401 public TCPEndpoint
getSourceEndpoint() {
403 TCPEndpoint endpoint
= fSourceEndpoint
;
404 if (endpoint
== null) {
405 endpoint
= new TCPEndpoint(this, true);
407 fSourceEndpoint
= endpoint
;
408 return fSourceEndpoint
;
412 public TCPEndpoint
getDestinationEndpoint() {
414 TCPEndpoint endpoint
= fDestinationEndpoint
;
416 if (endpoint
== null) {
417 endpoint
= new TCPEndpoint(this, false);
419 fDestinationEndpoint
= endpoint
;
420 return fDestinationEndpoint
;
424 public Map
<String
, String
> getFields() {
425 Map
<String
, String
> map
= fFields
;
427 Builder
<String
, String
> builder
= ImmutableMap
.<@NonNull String
, @NonNull String
> builder()
428 .put("Source Port", String
.valueOf(fSourcePort
)) //$NON-NLS-1$
429 .put("Destination Port", String
.valueOf(fDestinationPort
)) //$NON-NLS-1$
430 .put("Sequence Number", String
.valueOf(fSequenceNumber
)) //$NON-NLS-1$
431 .put("Acknowledgement Number", String
.valueOf(fAcknowledgmentNumber
)) //$NON-NLS-1$
432 .put("Length", String
.valueOf(fDataOffset
* TCPValues
.BLOCK_SIZE
) + " bytes") //$NON-NLS-1$ //$NON-NLS-2$
433 .put("ECN-Nonce Flag", String
.valueOf(fNSFlag
)) //$NON-NLS-1$
434 .put("Congestion Window Reduced Flag", String
.valueOf(fCWRFlag
)) //$NON-NLS-1$
435 .put("ECN-Echo Flag", String
.valueOf(fECEFlag
)) //$NON-NLS-1$
436 .put("Urgent Flag", String
.valueOf(fURGFlag
)) //$NON-NLS-1$
437 .put("ACK Flag", String
.valueOf(fACKFlag
)) //$NON-NLS-1$
438 .put("PSH Flag", String
.valueOf(fPSHFlag
)) //$NON-NLS-1$
439 .put("RST Flag", String
.valueOf(fRSTFlag
)) //$NON-NLS-1$
440 .put("SYN Flag", String
.valueOf(fSYNFlag
)) //$NON-NLS-1$
441 .put("FIN Flag", String
.valueOf(fFINFlag
)) //$NON-NLS-1$
442 .put("Window Size Value", String
.valueOf(fWindowSize
)) //$NON-NLS-1$
443 .put("Checksum", String
.format("%s%04x", "0x", fChecksum
)) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
444 .put("Urgent Pointer", String
.format("%s%04x", "0x", fUrgentPointer
)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
445 byte[] options
= fOptions
;
446 if (options
== null) {
447 builder
.put("Options", EMPTY_STRING
); //$NON-NLS-1$
449 builder
.put("Options", ConversionHelper
.bytesToHex(options
, true)); //$NON-NLS-1$
452 fFields
= builder
.build();
459 public String
getLocalSummaryString() {
460 return "Src Port: " + fSourcePort
+ ", Dst Port: " + fDestinationPort
+ //$NON-NLS-1$ //$NON-NLS-2$
461 ", Seq: " + fSequenceNumber
+ ", Ack: " + fAcknowledgmentNumber
+ //$NON-NLS-1$ //$NON-NLS-2$
462 ", Len: " + (fDataOffset
* TCPValues
.BLOCK_SIZE
); //$NON-NLS-1$ }
466 protected String
getSignificationString() {
467 StringBuilder sb
= new StringBuilder();
468 sb
.append(fSourcePort
)
469 .append(" > ") //$NON-NLS-1$
470 .append(fDestinationPort
);
472 if (!(generateFlagString().equals(EMPTY_STRING
))) {
475 .append(generateFlagString())
478 sb
.append(" Seq=") //$NON-NLS-1$
479 .append(fSequenceNumber
);
482 sb
.append(" Ack=") //$NON-NLS-1$
483 .append(fAcknowledgmentNumber
);
486 sb
.append(" Len=") //$NON-NLS-1$
487 .append((fDataOffset
* TCPValues
.BLOCK_SIZE
));
489 return NonNullUtils
.nullToEmptyString(sb
); }
491 private String
generateFlagString() {
492 StringBuilder sb
= new StringBuilder();
493 boolean start
= true;
497 sb
.append(", "); //$NON-NLS-1$
499 sb
.append("SYN"); //$NON-NLS-1$
504 sb
.append(", "); //$NON-NLS-1$
506 sb
.append("ACK"); //$NON-NLS-1$
511 sb
.append(", "); //$NON-NLS-1$
513 sb
.append("FIN"); //$NON-NLS-1$
518 sb
.append(", "); //$NON-NLS-1$
520 sb
.append("RST"); //$NON-NLS-1$
525 sb
.append(", "); //$NON-NLS-1$
527 sb
.append("PSH"); //$NON-NLS-1$
532 sb
.append(", "); //$NON-NLS-1$
534 sb
.append("URG"); //$NON-NLS-1$
539 sb
.append(", "); //$NON-NLS-1$
541 sb
.append("NS"); //$NON-NLS-1$
546 sb
.append(", "); //$NON-NLS-1$
548 sb
.append("CWR"); //$NON-NLS-1$
553 sb
.append(", "); //$NON-NLS-1$
555 sb
.append("ECE"); //$NON-NLS-1$
558 return NonNullUtils
.nullToEmptyString(sb
);
562 public int hashCode() {
563 final int prime
= 31;
565 result
= prime
* result
+ (fACKFlag ?
1231 : 1237);
566 result
= prime
* result
+ (int) (fAcknowledgmentNumber ^
(fAcknowledgmentNumber
>>> 32));
567 result
= prime
* result
+ (fCWRFlag ?
1231 : 1237);
568 result
= prime
* result
+ fChecksum
;
569 final Packet child
= fChildPacket
;
571 result
= prime
* result
+ child
.hashCode();
573 result
= prime
* result
;
575 result
= prime
* result
+ fDataOffset
;
576 result
= prime
* result
+ fDestinationPort
;
577 result
= prime
* result
+ (fECEFlag ?
1231 : 1237);
578 result
= prime
* result
+ (fFINFlag ?
1231 : 1237);
579 result
= prime
* result
+ (fNSFlag ?
1231 : 1237);
580 result
= prime
* result
+ Arrays
.hashCode(fOptions
);
581 result
= prime
* result
+ (fPSHFlag ?
1231 : 1237);
582 final ByteBuffer payload
= fPayload
;
583 if (payload
!= null) {
584 result
= prime
* result
+ payload
.hashCode();
586 result
= prime
* result
;
588 result
= prime
* result
+ (fRSTFlag ?
1231 : 1237);
589 result
= prime
* result
+ fReservedField
;
590 result
= prime
* result
+ (fSYNFlag ?
1231 : 1237);
591 result
= prime
* result
+ (int) (fSequenceNumber ^
(fSequenceNumber
>>> 32));
592 result
= prime
* result
+ fSourcePort
;
593 result
= prime
* result
+ (fURGFlag ?
1231 : 1237);
594 result
= prime
* result
+ fUrgentPointer
;
595 result
= prime
* result
+ fWindowSize
;
600 public boolean equals(@Nullable Object obj
) {
607 if (getClass() != obj
.getClass()) {
610 TCPPacket other
= (TCPPacket
) obj
;
611 if (fACKFlag
!= other
.fACKFlag
) {
614 if (fAcknowledgmentNumber
!= other
.fAcknowledgmentNumber
) {
617 if (fCWRFlag
!= other
.fCWRFlag
) {
620 if (fChecksum
!= other
.fChecksum
) {
623 if(!NonNullUtils
.equalsNullable(fChildPacket
, other
.fChildPacket
)){
626 if (fDataOffset
!= other
.fDataOffset
) {
629 if (fDestinationPort
!= other
.fDestinationPort
) {
632 if (fECEFlag
!= other
.fECEFlag
) {
635 if (fFINFlag
!= other
.fFINFlag
) {
638 if (fNSFlag
!= other
.fNSFlag
) {
641 if (!Arrays
.equals(fOptions
, other
.fOptions
)) {
644 if (fPSHFlag
!= other
.fPSHFlag
) {
647 if(!NonNullUtils
.equalsNullable(fPayload
, other
.fPayload
)){
650 if (fRSTFlag
!= other
.fRSTFlag
) {
653 if (fReservedField
!= other
.fReservedField
) {
656 if (fSYNFlag
!= other
.fSYNFlag
) {
659 if (fSequenceNumber
!= other
.fSequenceNumber
) {
662 if (fSourcePort
!= other
.fSourcePort
) {
665 if (fURGFlag
!= other
.fURGFlag
) {
668 if (fUrgentPointer
!= other
.fUrgentPointer
) {
671 if (fWindowSize
!= other
.fWindowSize
) {