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
.linuxtools
.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
.linuxtools
.pcap
.core
.packet
.BadPacketException
;
23 import org
.eclipse
.linuxtools
.pcap
.core
.packet
.Packet
;
24 import org
.eclipse
.linuxtools
.pcap
.core
.protocol
.Protocol
;
25 import org
.eclipse
.linuxtools
.pcap
.core
.protocol
.unknown
.UnknownPacket
;
26 import org
.eclipse
.linuxtools
.pcap
.core
.trace
.PcapFile
;
27 import org
.eclipse
.linuxtools
.pcap
.core
.util
.ConversionHelper
;
29 import com
.google
.common
.collect
.ImmutableMap
;
30 import com
.google
.common
.collect
.ImmutableMap
.Builder
;
33 * Class that represents a TCP packet.
35 * @author Vincent Perot
37 public class TCPPacket
extends Packet
{
39 private final @Nullable Packet fChildPacket
;
40 private final @Nullable ByteBuffer fPayload
;
42 private final int fSourcePort
;
43 private final int fDestinationPort
;
44 private final long fSequenceNumber
;
45 private final long fAcknowledgmentNumber
;
46 private final int fDataOffset
; // in 4 bytes block
47 private final byte fReservedField
;
48 private final boolean fNSFlag
;
49 private final boolean fCWRFlag
;
50 private final boolean fECEFlag
;
51 private final boolean fURGFlag
;
52 private final boolean fACKFlag
;
53 private final boolean fPSHFlag
;
54 private final boolean fRSTFlag
;
55 private final boolean fSYNFlag
;
56 private final boolean fFINFlag
;
57 private final int fWindowSize
;
58 private final int fChecksum
;
59 private final int fUrgentPointer
;
60 private final @Nullable byte[] fOptions
; // TODO Interpret options.
62 private @Nullable TCPEndpoint fSourceEndpoint
;
63 private @Nullable TCPEndpoint fDestinationEndpoint
;
65 private @Nullable ImmutableMap
<String
, String
> fFields
;
68 * Constructor of the TCP Packet class.
71 * The file that contains this packet.
73 * The parent packet of this packet (the encapsulating packet).
75 * The entire packet (header and payload).
76 * @throws BadPacketException
77 * Thrown when the packet is erroneous.
79 public TCPPacket(PcapFile file
, @Nullable Packet parent
, ByteBuffer packet
) throws BadPacketException
{
80 super(file
, parent
, Protocol
.TCP
);
82 // The endpoints are lazy loaded. They are defined in the get*Endpoint()
84 fSourceEndpoint
= null;
85 fDestinationEndpoint
= null;
89 packet
.order(ByteOrder
.BIG_ENDIAN
);
92 fSourcePort
= ConversionHelper
.unsignedShortToInt(packet
.getShort());
93 fDestinationPort
= ConversionHelper
.unsignedShortToInt(packet
.getShort());
94 fSequenceNumber
= ConversionHelper
.unsignedIntToLong(packet
.getInt());
95 fAcknowledgmentNumber
= ConversionHelper
.unsignedIntToLong(packet
.getInt());
97 byte storage
= packet
.get();
98 fDataOffset
= ((storage
& 0b11110000
) >>> 4) & 0x000000FF;
99 fReservedField
= (byte) ((storage
& 0b00001110
) >>> 1);
100 fNSFlag
= isBitSet(storage
, 0);
102 storage
= packet
.get();
103 fCWRFlag
= isBitSet(storage
, 7);
104 fECEFlag
= isBitSet(storage
, 6);
105 fURGFlag
= isBitSet(storage
, 5);
106 fACKFlag
= isBitSet(storage
, 4);
107 fPSHFlag
= isBitSet(storage
, 3);
108 fRSTFlag
= isBitSet(storage
, 2);
109 fSYNFlag
= isBitSet(storage
, 1);
110 fFINFlag
= isBitSet(storage
, 0);
112 fWindowSize
= ConversionHelper
.unsignedShortToInt(packet
.getShort());
113 fChecksum
= ConversionHelper
.unsignedShortToInt(packet
.getShort());
114 fUrgentPointer
= ConversionHelper
.unsignedShortToInt(packet
.getShort());
116 // Get options if any
117 if (fDataOffset
> TCPValues
.DEFAULT_HEADER_LENGTH
) {
118 fOptions
= new byte[(fDataOffset
- TCPValues
.DEFAULT_HEADER_LENGTH
) * TCPValues
.BLOCK_SIZE
];
119 packet
.get(fOptions
);
124 // Get payload if any.
125 if (packet
.array().length
- packet
.position() > 0) {
126 byte[] array
= new byte[packet
.array().length
- packet
.position()];
128 ByteBuffer payload
= ByteBuffer
.wrap(array
);
129 payload
.order(ByteOrder
.BIG_ENDIAN
);
137 fChildPacket
= findChildPacket();
142 public @Nullable Packet
getChildPacket() {
147 public @Nullable ByteBuffer
getPayload() {
154 * See http://www.iana.org/assignments/service-names-port-numbers/service-
155 * names-port-numbers.xhtml or
156 * http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
159 protected @Nullable Packet
findChildPacket() throws BadPacketException
{
160 // TODO implement further protocols and update this
161 ByteBuffer payload
= fPayload
;
162 if (payload
== null) {
166 return new UnknownPacket(getPcapFile(), this, payload
);
170 public String
toString() {
171 final ByteBuffer payload
= fPayload
;
173 if (payload
!= null) {
174 length
= payload
.array().length
;
177 String flagString
= ""; // TODO Finish it. Im just too lazy. //$NON-NLS-1$
178 String string
= getProtocol().getName() + ", Source Port: " + fSourcePort
+ ", Destination Port: " + fDestinationPort
+ //$NON-NLS-1$ //$NON-NLS-2$
179 "\nSequence Number: " + fSequenceNumber
+ ", Acknowledgment Number: " + fAcknowledgmentNumber
+ //$NON-NLS-1$ //$NON-NLS-2$
180 "\nHeader length: " + fDataOffset
* TCPValues
.BLOCK_SIZE
+ " bytes, Data length: " + length
+ //$NON-NLS-1$ //$NON-NLS-2$
181 "\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$
182 "\nChecksum: " + String
.format("%s%04x", "0x", fChecksum
) + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
183 final Packet child
= fChildPacket
;
185 return string
+ child
.toString();
191 * Getter method that returns the TCP Source Port.
193 * @return The source Port.
195 public int getSourcePort() {
200 * Getter method that returns the TCP Destination Port.
202 * @return The destination Port.
204 public int getDestinationPort() {
205 return fDestinationPort
;
209 * Getter method that returns the Sequence Number. The sequence number has a
212 * <li>If the SYN flag is set (1), then this is the initial sequence number.
213 * The sequence number of the actual first data byte and the acknowledged
214 * number in the corresponding ACK are then this sequence number plus 1.</li>
215 * <li>If the SYN flag is clear (0), then this is the accumulated sequence
216 * number of the first data byte of this segment for the current session.</li>
219 * Source: http://en.wikipedia.org/wiki/Transmission_Control_Protocol
221 * @return The Sequence Number.
223 public long getSequenceNumber() {
224 return fSequenceNumber
;
228 * Getter method that returns the Acknowledgment Number.
230 * If the ACK flag is set then the value of this field is the next sequence
231 * number that the receiver is expecting. This acknowledges receipt of all
232 * prior bytes (if any). The first ACK sent by each end acknowledges the
233 * other end's initial sequence number itself, but no data.
235 * Source: http://en.wikipedia.org/wiki/Transmission_Control_Protocol
237 * @return The Acknowledgment Number.
239 public long getAcknowledgmentNumber() {
240 return fAcknowledgmentNumber
;
244 * Getter method that returns the size of the TCP header in 4 bytes data
245 * block. The minimum size is 5 words and the maximum is 15 words.
247 * @return The Data Offset.
249 public int getDataOffset() {
254 * Getter method that returns the Reserved field. This field is for future
255 * use and should always be zero. In this library, it is used as a mean to
256 * verify the validity of a TCP packet.
258 * @return The Reserved Field.
260 public byte getReservedField() {
261 return fReservedField
;
265 * Getter method that returns the state of the NS flag.
267 * @return The state of the NS flag.
269 public boolean isNSFlagSet() {
274 * Getter method that returns the state of the CWR flag.
276 * @return The state of the CWR flag.
278 public boolean isCongestionWindowReducedFlagSet() {
283 * Getter method that returns the state of the ECE flag.
285 * @return The state of the ECE flag.
287 public boolean isECNEchoFlagSet() {
292 * Getter method that returns the state of the URG flag.
294 * @return The state of the URG flag.
296 public boolean isUrgentFlagSet() {
301 * Getter method that returns the state of the ACK flag.
303 * @return The state of the ACK flag.
305 public boolean isAcknowledgeFlagSet() {
310 * Getter method that returns the state of the PSH flag.
312 * @return The state of the PSH flag.
314 public boolean isPushFlagSet() {
319 * Getter method that returns the state of the RST flag.
321 * @return The state of the RST flag.
323 public boolean isResetFlagSet() {
328 * Getter method that returns the state of the SYN flag.
330 * @return The state of the SYN flag.
332 public boolean isSynchronizationFlagSet() {
337 * Getter method that returns the state of the FIN flag.
339 * @return The state of the FIN flag.
341 public boolean isFinalFlagSet() {
346 * Getter method that returns the size of the windows, in windows size unit
347 * (by default, bytes), that the sender of this packet is willing to
350 * @return The Window Size.
352 public int getWindowSize() {
357 * Getter method that returns the checksum of this packet. This checksum may
358 * be wrong if the packet is erroneous.
360 * @return The data and header checksum.
362 public int getChecksum() {
367 * Getter method that returns the Urgent Pointer. If the URG flag is set,
368 * this field is an offset from the sequence number indicating the last
371 * @return The Urgent Pointer.
373 public int getUrgentPointer() {
374 return fUrgentPointer
;
378 * Getter method that returns the options. This method returns null if no
379 * options are present.
381 * @return The options of the packet.
383 public @Nullable byte[] getOptions() {
384 byte[] options
= fOptions
;
385 if (options
== null) {
388 return Arrays
.copyOf(options
, options
.length
);
392 public boolean validate() {
393 // Not yet implemented. ATM, we consider that all packets are valid.
394 // This is the case for all packets.
395 // TODO Implement it.
400 public TCPEndpoint
getSourceEndpoint() {
402 TCPEndpoint endpoint
= fSourceEndpoint
;
403 if (endpoint
== null) {
404 endpoint
= new TCPEndpoint(this, true);
406 fSourceEndpoint
= endpoint
;
407 return fSourceEndpoint
;
411 public TCPEndpoint
getDestinationEndpoint() {
413 TCPEndpoint endpoint
= fDestinationEndpoint
;
415 if (endpoint
== null) {
416 endpoint
= new TCPEndpoint(this, false);
418 fDestinationEndpoint
= endpoint
;
419 return fDestinationEndpoint
;
423 public Map
<String
, String
> getFields() {
424 ImmutableMap
<String
, String
> map
= fFields
;
426 Builder
<String
, String
> builder
= ImmutableMap
.<String
, String
> builder()
427 .put("Source Port", String
.valueOf(fSourcePort
)) //$NON-NLS-1$
428 .put("Destination Port", String
.valueOf(fDestinationPort
)) //$NON-NLS-1$
429 .put("Sequence Number", String
.valueOf(fSequenceNumber
)) //$NON-NLS-1$
430 .put("Acknowledgement Number", String
.valueOf(fAcknowledgmentNumber
)) //$NON-NLS-1$
431 .put("Length", String
.valueOf(fDataOffset
* TCPValues
.BLOCK_SIZE
) + " bytes") //$NON-NLS-1$ //$NON-NLS-2$
432 .put("ECN-Nonce Flag", String
.valueOf(fNSFlag
)) //$NON-NLS-1$
433 .put("Congestion Window Reduced Flag", String
.valueOf(fCWRFlag
)) //$NON-NLS-1$
434 .put("ECN-Echo Flag", String
.valueOf(fECEFlag
)) //$NON-NLS-1$
435 .put("Urgent Flag", String
.valueOf(fURGFlag
)) //$NON-NLS-1$
436 .put("ACK Flag", String
.valueOf(fACKFlag
)) //$NON-NLS-1$
437 .put("PSH Flag", String
.valueOf(fPSHFlag
)) //$NON-NLS-1$
438 .put("RST Flag", String
.valueOf(fRSTFlag
)) //$NON-NLS-1$
439 .put("SYN Flag", String
.valueOf(fSYNFlag
)) //$NON-NLS-1$
440 .put("FIN Flag", String
.valueOf(fFINFlag
)) //$NON-NLS-1$
441 .put("Window Size Value", String
.valueOf(fWindowSize
)) //$NON-NLS-1$
442 .put("Checksum", String
.format("%s%04x", "0x", fChecksum
)) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
443 .put("Urgent Pointer", String
.format("%s%04x", "0x", fUrgentPointer
)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
444 byte[] options
= fOptions
;
445 if (options
== null) {
446 builder
.put("Options", EMPTY_STRING
); //$NON-NLS-1$
448 builder
.put("Options", ConversionHelper
.bytesToHex(options
, true)); //$NON-NLS-1$
451 @SuppressWarnings("null")
452 @NonNull ImmutableMap
<String
, String
> newMap
= 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 final ByteBuffer payload
= fPayload
;
488 if (payload
!= null) {
489 sb
.append(" Len=") //$NON-NLS-1$
490 .append(payload
.array().length
);
492 sb
.append(" Len=0"); //$NON-NLS-1$
495 String string
= sb
.toString();
496 if (string
== null) {
502 private String
generateFlagString() {
503 StringBuilder sb
= new StringBuilder();
504 boolean start
= true;
508 sb
.append(", "); //$NON-NLS-1$
510 sb
.append("SYN"); //$NON-NLS-1$
515 sb
.append(", "); //$NON-NLS-1$
517 sb
.append("ACK"); //$NON-NLS-1$
522 sb
.append(", "); //$NON-NLS-1$
524 sb
.append("FIN"); //$NON-NLS-1$
529 sb
.append(", "); //$NON-NLS-1$
531 sb
.append("RST"); //$NON-NLS-1$
536 sb
.append(", "); //$NON-NLS-1$
538 sb
.append("PSH"); //$NON-NLS-1$
543 sb
.append(", "); //$NON-NLS-1$
545 sb
.append("URG"); //$NON-NLS-1$
550 sb
.append(", "); //$NON-NLS-1$
552 sb
.append("NS"); //$NON-NLS-1$
557 sb
.append(", "); //$NON-NLS-1$
559 sb
.append("CWR"); //$NON-NLS-1$
564 sb
.append(", "); //$NON-NLS-1$
566 sb
.append("ECE"); //$NON-NLS-1$
569 String string
= sb
.toString();
570 if (string
== null) {
577 public int hashCode() {
578 final int prime
= 31;
580 result
= prime
* result
+ (fACKFlag ?
1231 : 1237);
581 result
= prime
* result
+ (int) (fAcknowledgmentNumber ^
(fAcknowledgmentNumber
>>> 32));
582 result
= prime
* result
+ (fCWRFlag ?
1231 : 1237);
583 result
= prime
* result
+ fChecksum
;
584 final Packet child
= fChildPacket
;
586 result
= prime
* result
+ child
.hashCode();
588 result
= prime
* result
;
590 result
= prime
* result
+ fDataOffset
;
591 result
= prime
* result
+ fDestinationPort
;
592 result
= prime
* result
+ (fECEFlag ?
1231 : 1237);
593 result
= prime
* result
+ (fFINFlag ?
1231 : 1237);
594 result
= prime
* result
+ (fNSFlag ?
1231 : 1237);
595 result
= prime
* result
+ Arrays
.hashCode(fOptions
);
596 result
= prime
* result
+ (fPSHFlag ?
1231 : 1237);
597 final ByteBuffer payload
= fPayload
;
598 if (payload
!= null) {
599 result
= prime
* result
+ payload
.hashCode();
601 result
= prime
* result
;
603 result
= prime
* result
+ (fRSTFlag ?
1231 : 1237);
604 result
= prime
* result
+ fReservedField
;
605 result
= prime
* result
+ (fSYNFlag ?
1231 : 1237);
606 result
= prime
* result
+ (int) (fSequenceNumber ^
(fSequenceNumber
>>> 32));
607 result
= prime
* result
+ fSourcePort
;
608 result
= prime
* result
+ (fURGFlag ?
1231 : 1237);
609 result
= prime
* result
+ fUrgentPointer
;
610 result
= prime
* result
+ fWindowSize
;
615 public boolean equals(@Nullable Object obj
) {
622 if (getClass() != obj
.getClass()) {
625 TCPPacket other
= (TCPPacket
) obj
;
626 if (fACKFlag
!= other
.fACKFlag
) {
629 if (fAcknowledgmentNumber
!= other
.fAcknowledgmentNumber
) {
632 if (fCWRFlag
!= other
.fCWRFlag
) {
635 if (fChecksum
!= other
.fChecksum
) {
638 final Packet child
= fChildPacket
;
640 if (!child
.equals(other
.fChildPacket
)) {
644 if (other
.fChildPacket
!= null) {
649 if (fDataOffset
!= other
.fDataOffset
) {
652 if (fDestinationPort
!= other
.fDestinationPort
) {
655 if (fECEFlag
!= other
.fECEFlag
) {
658 if (fFINFlag
!= other
.fFINFlag
) {
661 if (fNSFlag
!= other
.fNSFlag
) {
664 if (!Arrays
.equals(fOptions
, other
.fOptions
)) {
667 if (fPSHFlag
!= other
.fPSHFlag
) {
670 final ByteBuffer fPayload2
= fPayload
;
671 if (fPayload2
!= null) {
672 if (!fPayload2
.equals(other
.fPayload
)) {
676 if (other
.fPayload
!= null) {
680 if (fRSTFlag
!= other
.fRSTFlag
) {
683 if (fReservedField
!= other
.fReservedField
) {
686 if (fSYNFlag
!= other
.fSYNFlag
) {
689 if (fSequenceNumber
!= other
.fSequenceNumber
) {
692 if (fSourcePort
!= other
.fSourcePort
) {
695 if (fURGFlag
!= other
.fURGFlag
) {
698 if (fUrgentPointer
!= other
.fUrgentPointer
) {
701 if (fWindowSize
!= other
.fWindowSize
) {