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 static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
17 import java
.nio
.ByteBuffer
;
18 import java
.nio
.ByteOrder
;
19 import java
.util
.Arrays
;
22 import org
.eclipse
.jdt
.annotation
.Nullable
;
23 import org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
;
24 import org
.eclipse
.tracecompass
.internal
.pcap
.core
.packet
.BadPacketException
;
25 import org
.eclipse
.tracecompass
.internal
.pcap
.core
.packet
.Packet
;
26 import org
.eclipse
.tracecompass
.internal
.pcap
.core
.protocol
.PcapProtocol
;
27 import org
.eclipse
.tracecompass
.internal
.pcap
.core
.protocol
.unknown
.UnknownPacket
;
28 import org
.eclipse
.tracecompass
.internal
.pcap
.core
.trace
.PcapFile
;
29 import org
.eclipse
.tracecompass
.internal
.pcap
.core
.util
.ConversionHelper
;
31 import com
.google
.common
.collect
.ImmutableMap
;
32 import com
.google
.common
.collect
.ImmutableMap
.Builder
;
35 * Class that represents a TCP packet.
37 * @author Vincent Perot
39 public class TCPPacket
extends Packet
{
41 private final @Nullable Packet fChildPacket
;
42 private final @Nullable ByteBuffer fPayload
;
44 private final int fSourcePort
;
45 private final int fDestinationPort
;
46 private final long fSequenceNumber
;
47 private final long fAcknowledgmentNumber
;
48 private final int fDataOffset
; // in 4 bytes block
49 private final byte fReservedField
;
50 private final boolean fNSFlag
;
51 private final boolean fCWRFlag
;
52 private final boolean fECEFlag
;
53 private final boolean fURGFlag
;
54 private final boolean fACKFlag
;
55 private final boolean fPSHFlag
;
56 private final boolean fRSTFlag
;
57 private final boolean fSYNFlag
;
58 private final boolean fFINFlag
;
59 private final int fWindowSize
;
60 private final int fChecksum
;
61 private final int fUrgentPointer
;
62 private final @Nullable byte[] fOptions
; // TODO Interpret options.
64 private @Nullable TCPEndpoint fSourceEndpoint
;
65 private @Nullable TCPEndpoint fDestinationEndpoint
;
67 private @Nullable Map
<String
, String
> fFields
;
70 * Constructor of the TCP Packet class.
73 * The file that contains this packet.
75 * The parent packet of this packet (the encapsulating packet).
77 * The entire packet (header and payload).
78 * @throws BadPacketException
79 * Thrown when the packet is erroneous.
81 public TCPPacket(PcapFile file
, @Nullable Packet parent
, ByteBuffer packet
) throws BadPacketException
{
82 super(file
, parent
, PcapProtocol
.TCP
);
84 // The endpoints are lazy loaded. They are defined in the get*Endpoint()
86 fSourceEndpoint
= null;
87 fDestinationEndpoint
= null;
91 packet
.order(ByteOrder
.BIG_ENDIAN
);
94 fSourcePort
= ConversionHelper
.unsignedShortToInt(packet
.getShort());
95 fDestinationPort
= ConversionHelper
.unsignedShortToInt(packet
.getShort());
96 fSequenceNumber
= ConversionHelper
.unsignedIntToLong(packet
.getInt());
97 fAcknowledgmentNumber
= ConversionHelper
.unsignedIntToLong(packet
.getInt());
99 byte storage
= packet
.get();
100 fDataOffset
= ((storage
& 0b11110000
) >>> 4) & 0x000000FF;
101 fReservedField
= (byte) ((storage
& 0b00001110
) >>> 1);
102 fNSFlag
= isBitSet(storage
, 0);
104 storage
= packet
.get();
105 fCWRFlag
= isBitSet(storage
, 7);
106 fECEFlag
= isBitSet(storage
, 6);
107 fURGFlag
= isBitSet(storage
, 5);
108 fACKFlag
= isBitSet(storage
, 4);
109 fPSHFlag
= isBitSet(storage
, 3);
110 fRSTFlag
= isBitSet(storage
, 2);
111 fSYNFlag
= isBitSet(storage
, 1);
112 fFINFlag
= isBitSet(storage
, 0);
114 fWindowSize
= ConversionHelper
.unsignedShortToInt(packet
.getShort());
115 fChecksum
= ConversionHelper
.unsignedShortToInt(packet
.getShort());
116 fUrgentPointer
= ConversionHelper
.unsignedShortToInt(packet
.getShort());
118 // Get options if any
119 if (fDataOffset
> TCPValues
.DEFAULT_HEADER_LENGTH
) {
120 fOptions
= new byte[(fDataOffset
- TCPValues
.DEFAULT_HEADER_LENGTH
) * TCPValues
.BLOCK_SIZE
];
121 packet
.get(fOptions
);
126 // Get payload if any.
127 if (packet
.array().length
- packet
.position() > 0) {
128 byte[] array
= new byte[packet
.array().length
- packet
.position()];
130 ByteBuffer payload
= ByteBuffer
.wrap(array
);
131 payload
.order(ByteOrder
.BIG_ENDIAN
);
139 fChildPacket
= findChildPacket();
144 public @Nullable Packet
getChildPacket() {
149 public @Nullable ByteBuffer
getPayload() {
156 * See http://www.iana.org/assignments/service-names-port-numbers/service-
157 * names-port-numbers.xhtml or
158 * http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
161 protected @Nullable Packet
findChildPacket() throws BadPacketException
{
162 // TODO implement further protocols and update this
163 ByteBuffer payload
= fPayload
;
164 if (payload
== null) {
168 return new UnknownPacket(getPcapFile(), this, payload
);
172 public String
toString() {
173 final ByteBuffer payload
= fPayload
;
175 if (payload
!= null) {
176 length
= payload
.array().length
;
179 String flagString
= ""; // TODO Finish it. Im just too lazy. //$NON-NLS-1$
180 String string
= getProtocol().getName() + ", Source Port: " + fSourcePort
+ ", Destination Port: " + fDestinationPort
+ //$NON-NLS-1$ //$NON-NLS-2$
181 "\nSequence Number: " + fSequenceNumber
+ ", Acknowledgment Number: " + fAcknowledgmentNumber
+ //$NON-NLS-1$ //$NON-NLS-2$
182 "\nHeader length: " + fDataOffset
* TCPValues
.BLOCK_SIZE
+ " bytes, Data length: " + length
+ //$NON-NLS-1$ //$NON-NLS-2$
183 "\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$
184 "\nChecksum: " + String
.format("%s%04x", "0x", fChecksum
) + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
185 final Packet child
= fChildPacket
;
187 return string
+ child
.toString();
193 * Getter method that returns the TCP Source Port.
195 * @return The source Port.
197 public int getSourcePort() {
202 * Getter method that returns the TCP Destination Port.
204 * @return The destination Port.
206 public int getDestinationPort() {
207 return fDestinationPort
;
211 * Getter method that returns the Sequence Number. The sequence number has a
214 * <li>If the SYN flag is set (1), then this is the initial sequence number.
215 * The sequence number of the actual first data byte and the acknowledged
216 * number in the corresponding ACK are then this sequence number plus 1.</li>
217 * <li>If the SYN flag is clear (0), then this is the accumulated sequence
218 * number of the first data byte of this segment for the current session.</li>
221 * Source: http://en.wikipedia.org/wiki/Transmission_Control_Protocol
223 * @return The Sequence Number.
225 public long getSequenceNumber() {
226 return fSequenceNumber
;
230 * Getter method that returns the Acknowledgment Number.
232 * If the ACK flag is set then the value of this field is the next sequence
233 * number that the receiver is expecting. This acknowledges receipt of all
234 * prior bytes (if any). The first ACK sent by each end acknowledges the
235 * other end's initial sequence number itself, but no data.
237 * Source: http://en.wikipedia.org/wiki/Transmission_Control_Protocol
239 * @return The Acknowledgment Number.
241 public long getAcknowledgmentNumber() {
242 return fAcknowledgmentNumber
;
246 * Getter method that returns the size of the TCP header in 4 bytes data
247 * block. The minimum size is 5 words and the maximum is 15 words.
249 * @return The Data Offset.
251 public int getDataOffset() {
256 * Getter method that returns the Reserved field. This field is for future
257 * use and should always be zero. In this library, it is used as a mean to
258 * verify the validity of a TCP packet.
260 * @return The Reserved Field.
262 public byte getReservedField() {
263 return fReservedField
;
267 * Getter method that returns the state of the NS flag.
269 * @return The state of the NS flag.
271 public boolean isNSFlagSet() {
276 * Getter method that returns the state of the CWR flag.
278 * @return The state of the CWR flag.
280 public boolean isCongestionWindowReducedFlagSet() {
285 * Getter method that returns the state of the ECE flag.
287 * @return The state of the ECE flag.
289 public boolean isECNEchoFlagSet() {
294 * Getter method that returns the state of the URG flag.
296 * @return The state of the URG flag.
298 public boolean isUrgentFlagSet() {
303 * Getter method that returns the state of the ACK flag.
305 * @return The state of the ACK flag.
307 public boolean isAcknowledgeFlagSet() {
312 * Getter method that returns the state of the PSH flag.
314 * @return The state of the PSH flag.
316 public boolean isPushFlagSet() {
321 * Getter method that returns the state of the RST flag.
323 * @return The state of the RST flag.
325 public boolean isResetFlagSet() {
330 * Getter method that returns the state of the SYN flag.
332 * @return The state of the SYN flag.
334 public boolean isSynchronizationFlagSet() {
339 * Getter method that returns the state of the FIN flag.
341 * @return The state of the FIN flag.
343 public boolean isFinalFlagSet() {
348 * Getter method that returns the size of the windows, in windows size unit
349 * (by default, bytes), that the sender of this packet is willing to
352 * @return The Window Size.
354 public int getWindowSize() {
359 * Getter method that returns the checksum of this packet. This checksum may
360 * be wrong if the packet is erroneous.
362 * @return The data and header checksum.
364 public int getChecksum() {
369 * Getter method that returns the Urgent Pointer. If the URG flag is set,
370 * this field is an offset from the sequence number indicating the last
373 * @return The Urgent Pointer.
375 public int getUrgentPointer() {
376 return fUrgentPointer
;
380 * Getter method that returns the options. This method returns null if no
381 * options are present.
383 * @return The options of the packet.
385 public @Nullable byte[] getOptions() {
386 byte[] options
= fOptions
;
387 if (options
== null) {
390 return Arrays
.copyOf(options
, options
.length
);
394 public boolean validate() {
395 // Not yet implemented. ATM, we consider that all packets are valid.
396 // This is the case for all packets.
397 // TODO Implement it.
402 public TCPEndpoint
getSourceEndpoint() {
404 TCPEndpoint endpoint
= fSourceEndpoint
;
405 if (endpoint
== null) {
406 endpoint
= new TCPEndpoint(this, true);
408 fSourceEndpoint
= endpoint
;
409 return fSourceEndpoint
;
413 public TCPEndpoint
getDestinationEndpoint() {
415 TCPEndpoint endpoint
= fDestinationEndpoint
;
417 if (endpoint
== null) {
418 endpoint
= new TCPEndpoint(this, false);
420 fDestinationEndpoint
= endpoint
;
421 return fDestinationEndpoint
;
425 public Map
<String
, String
> getFields() {
426 Map
<String
, String
> map
= fFields
;
428 Builder
<String
, String
> builder
= ImmutableMap
.<String
, String
> builder()
429 .put("Source Port", String
.valueOf(fSourcePort
)) //$NON-NLS-1$
430 .put("Destination Port", String
.valueOf(fDestinationPort
)) //$NON-NLS-1$
431 .put("Sequence Number", String
.valueOf(fSequenceNumber
)) //$NON-NLS-1$
432 .put("Acknowledgement Number", String
.valueOf(fAcknowledgmentNumber
)) //$NON-NLS-1$
433 .put("Length", String
.valueOf(fDataOffset
* TCPValues
.BLOCK_SIZE
) + " bytes") //$NON-NLS-1$ //$NON-NLS-2$
434 .put("ECN-Nonce Flag", String
.valueOf(fNSFlag
)) //$NON-NLS-1$
435 .put("Congestion Window Reduced Flag", String
.valueOf(fCWRFlag
)) //$NON-NLS-1$
436 .put("ECN-Echo Flag", String
.valueOf(fECEFlag
)) //$NON-NLS-1$
437 .put("Urgent Flag", String
.valueOf(fURGFlag
)) //$NON-NLS-1$
438 .put("ACK Flag", String
.valueOf(fACKFlag
)) //$NON-NLS-1$
439 .put("PSH Flag", String
.valueOf(fPSHFlag
)) //$NON-NLS-1$
440 .put("RST Flag", String
.valueOf(fRSTFlag
)) //$NON-NLS-1$
441 .put("SYN Flag", String
.valueOf(fSYNFlag
)) //$NON-NLS-1$
442 .put("FIN Flag", String
.valueOf(fFINFlag
)) //$NON-NLS-1$
443 .put("Window Size Value", String
.valueOf(fWindowSize
)) //$NON-NLS-1$
444 .put("Checksum", String
.format("%s%04x", "0x", fChecksum
)) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
445 .put("Urgent Pointer", String
.format("%s%04x", "0x", fUrgentPointer
)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
446 byte[] options
= fOptions
;
447 if (options
== null) {
448 builder
.put("Options", EMPTY_STRING
); //$NON-NLS-1$
450 builder
.put("Options", ConversionHelper
.bytesToHex(options
, true)); //$NON-NLS-1$
453 fFields
= checkNotNull(builder
.build());
460 public String
getLocalSummaryString() {
461 return "Src Port: " + fSourcePort
+ ", Dst Port: " + fDestinationPort
+ //$NON-NLS-1$ //$NON-NLS-2$
462 ", Seq: " + fSequenceNumber
+ ", Ack: " + fAcknowledgmentNumber
+ //$NON-NLS-1$ //$NON-NLS-2$
463 ", Len: " + (fDataOffset
* TCPValues
.BLOCK_SIZE
); //$NON-NLS-1$ }
467 protected String
getSignificationString() {
468 StringBuilder sb
= new StringBuilder();
469 sb
.append(fSourcePort
)
470 .append(" > ") //$NON-NLS-1$
471 .append(fDestinationPort
);
473 if (!(generateFlagString().equals(EMPTY_STRING
))) {
476 .append(generateFlagString())
479 sb
.append(" Seq=") //$NON-NLS-1$
480 .append(fSequenceNumber
);
483 sb
.append(" Ack=") //$NON-NLS-1$
484 .append(fAcknowledgmentNumber
);
487 sb
.append(" Len=") //$NON-NLS-1$
488 .append((fDataOffset
* TCPValues
.BLOCK_SIZE
));
490 return NonNullUtils
.nullToEmptyString(sb
); }
492 private String
generateFlagString() {
493 StringBuilder sb
= new StringBuilder();
494 boolean start
= true;
498 sb
.append(", "); //$NON-NLS-1$
500 sb
.append("SYN"); //$NON-NLS-1$
505 sb
.append(", "); //$NON-NLS-1$
507 sb
.append("ACK"); //$NON-NLS-1$
512 sb
.append(", "); //$NON-NLS-1$
514 sb
.append("FIN"); //$NON-NLS-1$
519 sb
.append(", "); //$NON-NLS-1$
521 sb
.append("RST"); //$NON-NLS-1$
526 sb
.append(", "); //$NON-NLS-1$
528 sb
.append("PSH"); //$NON-NLS-1$
533 sb
.append(", "); //$NON-NLS-1$
535 sb
.append("URG"); //$NON-NLS-1$
540 sb
.append(", "); //$NON-NLS-1$
542 sb
.append("NS"); //$NON-NLS-1$
547 sb
.append(", "); //$NON-NLS-1$
549 sb
.append("CWR"); //$NON-NLS-1$
554 sb
.append(", "); //$NON-NLS-1$
556 sb
.append("ECE"); //$NON-NLS-1$
559 return NonNullUtils
.nullToEmptyString(sb
);
563 public int hashCode() {
564 final int prime
= 31;
566 result
= prime
* result
+ (fACKFlag ?
1231 : 1237);
567 result
= prime
* result
+ (int) (fAcknowledgmentNumber ^
(fAcknowledgmentNumber
>>> 32));
568 result
= prime
* result
+ (fCWRFlag ?
1231 : 1237);
569 result
= prime
* result
+ fChecksum
;
570 final Packet child
= fChildPacket
;
572 result
= prime
* result
+ child
.hashCode();
574 result
= prime
* result
;
576 result
= prime
* result
+ fDataOffset
;
577 result
= prime
* result
+ fDestinationPort
;
578 result
= prime
* result
+ (fECEFlag ?
1231 : 1237);
579 result
= prime
* result
+ (fFINFlag ?
1231 : 1237);
580 result
= prime
* result
+ (fNSFlag ?
1231 : 1237);
581 result
= prime
* result
+ Arrays
.hashCode(fOptions
);
582 result
= prime
* result
+ (fPSHFlag ?
1231 : 1237);
583 final ByteBuffer payload
= fPayload
;
584 if (payload
!= null) {
585 result
= prime
* result
+ payload
.hashCode();
587 result
= prime
* result
;
589 result
= prime
* result
+ (fRSTFlag ?
1231 : 1237);
590 result
= prime
* result
+ fReservedField
;
591 result
= prime
* result
+ (fSYNFlag ?
1231 : 1237);
592 result
= prime
* result
+ (int) (fSequenceNumber ^
(fSequenceNumber
>>> 32));
593 result
= prime
* result
+ fSourcePort
;
594 result
= prime
* result
+ (fURGFlag ?
1231 : 1237);
595 result
= prime
* result
+ fUrgentPointer
;
596 result
= prime
* result
+ fWindowSize
;
601 public boolean equals(@Nullable Object obj
) {
608 if (getClass() != obj
.getClass()) {
611 TCPPacket other
= (TCPPacket
) obj
;
612 if (fACKFlag
!= other
.fACKFlag
) {
615 if (fAcknowledgmentNumber
!= other
.fAcknowledgmentNumber
) {
618 if (fCWRFlag
!= other
.fCWRFlag
) {
621 if (fChecksum
!= other
.fChecksum
) {
624 if(!NonNullUtils
.equalsNullable(fChildPacket
, other
.fChildPacket
)){
627 if (fDataOffset
!= other
.fDataOffset
) {
630 if (fDestinationPort
!= other
.fDestinationPort
) {
633 if (fECEFlag
!= other
.fECEFlag
) {
636 if (fFINFlag
!= other
.fFINFlag
) {
639 if (fNSFlag
!= other
.fNSFlag
) {
642 if (!Arrays
.equals(fOptions
, other
.fOptions
)) {
645 if (fPSHFlag
!= other
.fPSHFlag
) {
648 if(!NonNullUtils
.equalsNullable(fPayload
, other
.fPayload
)){
651 if (fRSTFlag
!= other
.fRSTFlag
) {
654 if (fReservedField
!= other
.fReservedField
) {
657 if (fSYNFlag
!= other
.fSYNFlag
) {
660 if (fSequenceNumber
!= other
.fSequenceNumber
) {
663 if (fSourcePort
!= other
.fSourcePort
) {
666 if (fURGFlag
!= other
.fURGFlag
) {
669 if (fUrgentPointer
!= other
.fUrgentPointer
) {
672 if (fWindowSize
!= other
.fWindowSize
) {