tmf: Initial commit of Pcap Parser
[deliverable/tracecompass.git] / org.eclipse.linuxtools.pcap.core / src / org / eclipse / linuxtools / pcap / core / protocol / ipv4 / IPv4Packet.java
1 /*******************************************************************************
2 * Copyright (c) 2014 Ericsson
3 *
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
8 *
9 * Contributors:
10 * Vincent Perot - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.pcap.core.protocol.ipv4;
14
15 import java.nio.ByteBuffer;
16 import java.nio.ByteOrder;
17 import java.util.Arrays;
18 import java.util.Map;
19
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.tcp.TCPPacket;
26 import org.eclipse.linuxtools.pcap.core.protocol.udp.UDPPacket;
27 import org.eclipse.linuxtools.pcap.core.protocol.unknown.UnknownPacket;
28 import org.eclipse.linuxtools.pcap.core.trace.PcapFile;
29 import org.eclipse.linuxtools.pcap.core.util.ConversionHelper;
30 import org.eclipse.linuxtools.pcap.core.util.IPProtocolNumberHelper;
31
32 import com.google.common.collect.ImmutableMap;
33 import com.google.common.collect.ImmutableMap.Builder;
34
35 /**
36 * Class that represents an Ethernet II packet.
37 *
38 * @author Vincent Perot
39 */
40 public class IPv4Packet extends Packet {
41
42 private final @Nullable Packet fChildPacket;
43 private final @Nullable ByteBuffer fPayload;
44
45 private final int fVersion;
46 private final int fInternetHeaderLength; // in 4 bytes blocks
47 private final int fDSCP;
48 private final int fExplicitCongestionNotification;
49 private final int fTotalLength; // in bytes
50 private final int fIdentification;
51 private final boolean fReservedFlag;
52 private final boolean fDontFragmentFlag;
53 private final boolean fMoreFragmentFlag;
54 private final int fFragmentOffset;
55 private final int fTimeToLive;
56 private final int fIpDatagramProtocol;
57 private final int fHeaderChecksum;
58 private final byte[] fSourceIpAddress;
59 private final byte[] fDestinationIpAddress;
60 private final @Nullable byte[] fOptions;
61
62 private @Nullable IPv4Endpoint fSourceEndpoint;
63 private @Nullable IPv4Endpoint fDestinationEndpoint;
64
65 private @Nullable ImmutableMap<String, String> fFields;
66
67 // TODO Interpret options. See
68 // http://www.iana.org/assignments/ip-parameters/ip-parameters.xhtml
69
70 /**
71 * Constructor of the IPv4 Packet class.
72 *
73 * @param file
74 * The file that contains this packet.
75 * @param parent
76 * The parent packet of this packet (the encapsulating packet).
77 * @param packet
78 * The entire packet (header and payload).
79 * @throws BadPacketException
80 * Thrown when the packet is erroneous.
81 */
82 public IPv4Packet(PcapFile file, @Nullable Packet parent, ByteBuffer packet) throws BadPacketException {
83 super(file, parent, Protocol.IPV4);
84
85 // The endpoints are lazy loaded. They are defined in the get*Endpoint()
86 // methods.
87 fSourceEndpoint = null;
88 fDestinationEndpoint = null;
89
90 fFields = null;
91
92 packet.order(ByteOrder.BIG_ENDIAN);
93 packet.position(0);
94
95 byte storage = packet.get();
96 fVersion = ((storage & 0xF0) >> 4) & 0x000000FF;
97 fInternetHeaderLength = storage & 0x0F;
98
99 storage = packet.get();
100 fDSCP = ((storage & 0b11111100) >> 2) & 0x000000FF;
101 fExplicitCongestionNotification = storage & 0b00000011;
102
103 fTotalLength = ConversionHelper.unsignedShortToInt(packet.getShort());
104 fIdentification = ConversionHelper.unsignedShortToInt(packet.getShort());
105
106 storage = packet.get();
107 fReservedFlag = isBitSet(storage, 7);
108 fDontFragmentFlag = isBitSet(storage, 6);
109 fMoreFragmentFlag = isBitSet(storage, 5);
110 fFragmentOffset = ((storage & 0b00011111) << 8) | packet.get();
111
112 fTimeToLive = ConversionHelper.unsignedByteToInt(packet.get());
113 fIpDatagramProtocol = ConversionHelper.unsignedByteToInt(packet.get());
114 fHeaderChecksum = ConversionHelper.unsignedShortToInt(packet.getShort());
115
116 fSourceIpAddress = new byte[IPv4Values.IP_ADDRESS_SIZE];
117 fDestinationIpAddress = new byte[IPv4Values.IP_ADDRESS_SIZE];
118 packet.get(fSourceIpAddress);
119 packet.get(fDestinationIpAddress);
120
121 // Get options if there are any
122 if (fInternetHeaderLength > IPv4Values.DEFAULT_HEADER_LENGTH) {
123 fOptions = new byte[(fInternetHeaderLength - IPv4Values.DEFAULT_HEADER_LENGTH) * IPv4Values.BLOCK_SIZE];
124 packet.get(fOptions);
125 } else {
126 fOptions = null;
127 }
128
129 // Get payload if any.
130 if (packet.array().length - packet.position() > 0) {
131 byte[] array = new byte[packet.array().length - packet.position()];
132 packet.get(array);
133 ByteBuffer payload = ByteBuffer.wrap(array);
134 payload.order(ByteOrder.BIG_ENDIAN);
135 payload.position(0);
136 fPayload = payload;
137 } else {
138 fPayload = null;
139 }
140
141 // Find child
142 fChildPacket = findChildPacket();
143
144 }
145
146 @Override
147 public @Nullable Packet getChildPacket() {
148 return fChildPacket;
149 }
150
151 @Override
152 public @Nullable ByteBuffer getPayload() {
153 return fPayload;
154 }
155
156 /**
157 * {@inheritDoc}
158 *
159 * See http://en.wikipedia.org/wiki/List_of_IP_protocol_numbers
160 */
161 @Override
162 protected @Nullable Packet findChildPacket() throws BadPacketException {
163 // TODO Implement more protocols
164 ByteBuffer payload = fPayload;
165 if (payload == null) {
166 return null;
167 }
168
169 switch (fIpDatagramProtocol) {
170 case IPProtocolNumberHelper.PROTOCOL_NUMBER_TCP:
171 return new TCPPacket(getPcapFile(), this, payload);
172 case IPProtocolNumberHelper.PROTOCOL_NUMBER_UDP:
173 return new UDPPacket(getPcapFile(), this, payload);
174 default:
175 return new UnknownPacket(getPcapFile(), this, payload);
176 }
177
178 }
179
180 @Override
181 public String toString() {
182 // Generate flagString
183 // This is very ugly.
184 String flagString = null;
185
186 if (fReservedFlag && fDontFragmentFlag && fMoreFragmentFlag) { // 111
187 flagString = "Flags: 0x07 (Invalid)"; //$NON-NLS-1$
188 } else if (fReservedFlag && fDontFragmentFlag && !fMoreFragmentFlag) { // 110
189 flagString = "Flags: 0x06 (Invalid)"; //$NON-NLS-1$
190 } else if (fReservedFlag && !fDontFragmentFlag && fMoreFragmentFlag) { // 101
191 flagString = "Flags: 0x05 (Invalid)"; //$NON-NLS-1$
192 } else if (fReservedFlag && !fDontFragmentFlag && !fMoreFragmentFlag) { // 100
193 flagString = "Flags: 0x04 (Invalid)"; //$NON-NLS-1$
194 } else if (!fReservedFlag && fDontFragmentFlag && fMoreFragmentFlag) { // 011
195 flagString = "Flags: 0x03 (Invalid)"; //$NON-NLS-1$
196 } else if (!fReservedFlag && fDontFragmentFlag && !fMoreFragmentFlag) { // 010
197 flagString = "Flags: 0x02 (Don't fragment)"; //$NON-NLS-1$
198 } else if (!fReservedFlag && !fDontFragmentFlag && fMoreFragmentFlag) { // 001
199 flagString = "Flags: 0x01 (More fragments)"; //$NON-NLS-1$
200 } else if (!fReservedFlag && !fDontFragmentFlag && !fMoreFragmentFlag) { // 000
201 flagString = "Flags: 0x00 (Don't have more fragments)"; //$NON-NLS-1$
202 }
203
204 flagString += ", Fragment Offset: " + fFragmentOffset; //$NON-NLS-1$
205
206 // Generate checksum string
207 // TODO calculate the expected checksum from packet
208 String checksumString = "Header Checksum: " + String.format("%s%04x", "0x", fHeaderChecksum); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
209
210 String string = getProtocol().getName() + ", Source: " + ConversionHelper.toIpAddress(fSourceIpAddress) + ", Destination: " + ConversionHelper.toIpAddress(fDestinationIpAddress) + //$NON-NLS-1$ //$NON-NLS-2$
211 "\nVersion: " + fVersion + ", Identification: " + String.format("%s%04x", "0x", fIdentification) + ", Header Length: " + getHeaderLength() + " bytes, Total Length: " + getTotalLength() + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
212 " bytes\nDifferentiated Services Code Point: " + String.format("%s%02x", "0x", fDSCP) + "; Explicit Congestion Notification: " + String.format("%s%02x", "0x", fExplicitCongestionNotification) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
213 + "\n" + flagString + "\nTime to live: " + fTimeToLive + //$NON-NLS-1$ //$NON-NLS-2$
214 "\nProtocol: " + fIpDatagramProtocol + "\n" //$NON-NLS-1$ //$NON-NLS-2$
215 + checksumString + "\n"; //$NON-NLS-1$
216 final Packet child = fChildPacket;
217 if (child != null) {
218 return string + child.toString();
219 }
220 return string;
221 }
222
223 /**
224 * Getter method that returns the version of the IP protocol used. This
225 * should always be set to 4 as IPv6 has its own class.
226 *
227 * @return The version of the IP used.
228 */
229 public int getVersion() {
230 return fVersion;
231 }
232
233 /**
234 * Getter method that returns the header length in bytes. In the IPv4
235 * packet, this is specified in 4-bytes data block. By default, this method
236 * returns 20 if there are no options present. Otherwise, it will return a
237 * higher number.
238 *
239 * @return The header length in bytes.
240 */
241 public int getHeaderLength() {
242 return fInternetHeaderLength * IPv4Values.BLOCK_SIZE;
243 }
244
245 /**
246 * Getter method that returns the Differentiated Services Code Point (a.k.a.
247 * the Type of Service). This is useful for some technologies that require
248 * real-time data exchange.
249 *
250 * @return The DSCP
251 */
252 public int getDSCP() {
253 return fDSCP;
254 }
255
256 /**
257 * Getter method that returns the Explicit Congestion Notification (ECN).
258 * This allows end-to-end communication without dropping packets.
259 *
260 * @return The ECN.
261 */
262 public int getExplicitCongestionNotification() {
263 return fExplicitCongestionNotification;
264 }
265
266 /**
267 * Getter method to retrieve the length of the entire packet, in bytes. This
268 * number is according to the packet, and might not be true if the packet is
269 * erroneous.
270 *
271 * @return The total length (packet and payload) in bytes.
272 */
273 public int getTotalLength() {
274 return fTotalLength;
275 }
276
277 /**
278 * Getter method to retrieve the Identification. This is a field that is
279 * used to uniquely identify the packets, thus allowing the reconstruction
280 * of fragmented IP packets.
281 *
282 * @return The packet identification.
283 */
284 public int getIdentification() {
285 return fIdentification;
286 }
287
288 /**
289 * Getter method that returns the state of the Reserved flag. This must
290 * always be zero.
291 *
292 * @return The state of the Reserved flag.
293 */
294 public boolean getReservedFlag() {
295 return fReservedFlag;
296 }
297
298 /**
299 * Getter method that indicates if the packet can be fragmented or not.
300 *
301 * @return Whether the packet can be fragmented or not.
302 */
303 public boolean getDontFragmentFlag() {
304 return fDontFragmentFlag;
305 }
306
307 /**
308 * Getter method that indicates if the packet has more fragments or not.
309 *
310 * @return Whether the packet has more fragments or not.
311 */
312 public boolean getHasMoreFragment() {
313 return fMoreFragmentFlag;
314 }
315
316 /**
317 * Getter method that specify the offset of a particular fragment relative
318 * to the original unfragmented packet, in 8-bytes blocks. *
319 *
320 * @return The fragment offset.
321 */
322 public int getFragmentOffset() {
323 return fFragmentOffset;
324 }
325
326 /**
327 * Getter method that returns the time to live in seconds. In practice, this
328 * is a hop count. This is used to prevent packets from persisting.
329 *
330 * @return The time left to live for the packet.
331 */
332 public int getTimeToLive() {
333 return fTimeToLive;
334 }
335
336 /**
337 * Getter method that returns the encapsulated protocol.
338 *
339 * See http://en.wikipedia.org/wiki/List_of_IP_protocol_numbers
340 *
341 * @return The encapsulated protocol.
342 */
343 public int getIpDatagramProtocol() {
344 return fIpDatagramProtocol;
345 }
346
347 /**
348 * Getter method that returns the checksum, according to the packet. This
349 * checksum might be wrong if the packet is erroneous.
350 *
351 * @return The header checksum.
352 */
353 public int getHeaderChecksum() {
354 return fHeaderChecksum;
355 }
356
357 /**
358 * Getter method that returns the source IP address.
359 *
360 * @return The source IP address, as a byte array in big-endian.
361 */
362 public byte[] getSourceIpAddress() {
363 return fSourceIpAddress;
364 }
365
366 /**
367 * Getter method that returns the destination IP address.
368 *
369 * @return The destination IP address, as a byte array in big-endian.
370 */
371 public byte[] getDestinationIpAddress() {
372 return fDestinationIpAddress;
373 }
374
375 /**
376 * Getter method that returns the options. This method returns null if no
377 * options are present.
378 *
379 * @return The options of the packet.
380 */
381 public @Nullable byte[] getOptions() {
382 final byte[] options = fOptions;
383 if (options == null) {
384 return null;
385 }
386 return Arrays.copyOf(options, options.length);
387 }
388
389 @Override
390 public boolean validate() {
391 // Not yet implemented. ATM, we consider that all packets are valid.
392 // This is the case for all packets.
393 // TODO Implement it.
394 return true;
395 }
396
397 @Override
398 public IPv4Endpoint getSourceEndpoint() {
399 @Nullable
400 IPv4Endpoint endpoint = fSourceEndpoint;
401 if (endpoint == null) {
402 endpoint = new IPv4Endpoint(this, true);
403 }
404 fSourceEndpoint = endpoint;
405 return fSourceEndpoint;
406 }
407
408 @Override
409 public IPv4Endpoint getDestinationEndpoint() {
410 @Nullable
411 IPv4Endpoint endpoint = fDestinationEndpoint;
412
413 if (endpoint == null) {
414 endpoint = new IPv4Endpoint(this, false);
415 }
416 fDestinationEndpoint = endpoint;
417 return fDestinationEndpoint;
418 }
419
420 @Override
421 public Map<String, String> getFields() {
422 ImmutableMap<String, String> map = fFields;
423 if (map == null) {
424 Builder<String, String> builder = ImmutableMap.<String, String> builder()
425 .put("Version", String.valueOf(fVersion)) //$NON-NLS-1$
426 .put("Header Length", String.valueOf(getHeaderLength()) + " bytes") //$NON-NLS-1$ //$NON-NLS-2$
427 .put("Differentiated Services Field", String.format("%s%02x", "0x", fDSCP)) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
428 .put("Explicit Congestion Notification", String.format("%s%02x", "0x", fExplicitCongestionNotification)) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
429 .put("Total Length", String.valueOf(fTotalLength) + " bytes") //$NON-NLS-1$ //$NON-NLS-2$
430 .put("Identification", String.format("%s%04x", "0x", fIdentification)) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
431 .put("Don't Fragment Flag", String.valueOf(fDontFragmentFlag)) //$NON-NLS-1$
432 .put("More Fragment Flag", String.valueOf(fMoreFragmentFlag)) //$NON-NLS-1$
433 .put("Fragment Offset", String.valueOf(fFragmentOffset)) //$NON-NLS-1$
434 .put("Time to live", String.valueOf(fTimeToLive)) //$NON-NLS-1$
435 .put("Protocol", IPProtocolNumberHelper.toString(fIpDatagramProtocol) + " (" + String.valueOf(fIpDatagramProtocol) + ")") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
436 .put("Checksum", String.format("%s%04x", "0x", fHeaderChecksum)) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
437 .put("Source IP Address", ConversionHelper.toIpAddress(fSourceIpAddress)) //$NON-NLS-1$
438 .put("Destination IP Address", ConversionHelper.toIpAddress(fDestinationIpAddress)); //$NON-NLS-1$
439 byte[] options = fOptions;
440 if (options == null) {
441 builder.put("Options", EMPTY_STRING); //$NON-NLS-1$
442 } else {
443 builder.put("Options", ConversionHelper.bytesToHex(options, true)); //$NON-NLS-1$
444
445 }
446 @SuppressWarnings("null")
447 @NonNull
448 ImmutableMap<String, String> newMap = builder.build();
449 fFields = newMap;
450 return newMap;
451 }
452 return map;
453 }
454
455 @Override
456 public String getLocalSummaryString() {
457 return "Src: " + ConversionHelper.toIpAddress(fSourceIpAddress) + " , Dst: " + ConversionHelper.toIpAddress(fDestinationIpAddress); //$NON-NLS-1$ //$NON-NLS-2$
458 }
459
460 @Override
461 protected String getSignificationString() {
462 StringBuilder sb = new StringBuilder();
463 sb.append(ConversionHelper.toIpAddress(fSourceIpAddress))
464 .append(" > ") //$NON-NLS-1$
465 .append(ConversionHelper.toIpAddress(fDestinationIpAddress));
466
467 String flags = generateFlagString();
468 if (!(flags.equals(""))) { //$NON-NLS-1$
469 sb.append(' ')
470 .append('[')
471 .append(flags)
472 .append(']');
473 }
474 sb.append(" Id=") //$NON-NLS-1$
475 .append(fIdentification);
476
477 final ByteBuffer payload = fPayload;
478 if (payload != null) {
479 sb.append(" Len=") //$NON-NLS-1$
480 .append(payload.array().length);
481 } else {
482 sb.append(" Len=0"); //$NON-NLS-1$
483 }
484 String string = sb.toString();
485 if (string == null) {
486 return EMPTY_STRING;
487 }
488 return string;
489 }
490
491 private String generateFlagString() {
492 StringBuilder sb = new StringBuilder();
493 boolean start = true;
494
495 if (fDontFragmentFlag) {
496 if (!start) {
497 sb.append(", "); //$NON-NLS-1$
498 }
499 sb.append("DF"); //$NON-NLS-1$
500 start = false;
501 }
502 if (fMoreFragmentFlag) {
503 if (!start) {
504 sb.append(", "); //$NON-NLS-1$
505 }
506 sb.append("MF"); //$NON-NLS-1$
507 start = false;
508 }
509 String string = sb.toString();
510 if (string == null) {
511 return EMPTY_STRING;
512 }
513 return string;
514 }
515
516 @Override
517 public int hashCode() {
518 final int prime = 31;
519 int result = 1;
520 final Packet child = fChildPacket;
521 if (child != null) {
522 result = prime * result + child.hashCode();
523 } else {
524 result = prime * result;
525 }
526 result = prime * result + fDSCP;
527 result = prime * result + Arrays.hashCode(fDestinationIpAddress);
528 result = prime * result + (fDontFragmentFlag ? 1231 : 1237);
529 result = prime * result + fExplicitCongestionNotification;
530 result = prime * result + fFragmentOffset;
531 result = prime * result + fHeaderChecksum;
532 result = prime * result + fIdentification;
533 result = prime * result + fInternetHeaderLength;
534 result = prime * result + fIpDatagramProtocol;
535 result = prime * result + (fMoreFragmentFlag ? 1231 : 1237);
536 result = prime * result + Arrays.hashCode(fOptions);
537 final ByteBuffer payload = fPayload;
538 if (payload != null) {
539 result = prime * result + payload.hashCode();
540 } else {
541 result = prime * result;
542 }
543 result = prime * result + (fReservedFlag ? 1231 : 1237);
544 result = prime * result + Arrays.hashCode(fSourceIpAddress);
545 result = prime * result + fTimeToLive;
546 result = prime * result + fTotalLength;
547 result = prime * result + fVersion;
548 return result;
549 }
550
551 @Override
552 public boolean equals(@Nullable Object obj) {
553 if (this == obj) {
554 return true;
555 }
556 if (obj == null) {
557 return false;
558 }
559 if (getClass() != obj.getClass()) {
560 return false;
561 }
562 IPv4Packet other = (IPv4Packet) obj;
563 final Packet child = fChildPacket;
564 if (child != null) {
565 if (!child.equals(other.fChildPacket)) {
566 return false;
567 }
568 } else {
569 if (other.fChildPacket != null) {
570 return false;
571 }
572 }
573
574 if (fDSCP != other.fDSCP) {
575 return false;
576 }
577 if (!Arrays.equals(fDestinationIpAddress, other.fDestinationIpAddress)) {
578 return false;
579 }
580 if (fDontFragmentFlag != other.fDontFragmentFlag) {
581 return false;
582 }
583 if (fExplicitCongestionNotification != other.fExplicitCongestionNotification) {
584 return false;
585 }
586 if (fFragmentOffset != other.fFragmentOffset) {
587 return false;
588 }
589 if (fHeaderChecksum != other.fHeaderChecksum) {
590 return false;
591 }
592 if (fIdentification != other.fIdentification) {
593 return false;
594 }
595 if (fInternetHeaderLength != other.fInternetHeaderLength) {
596 return false;
597 }
598 if (fIpDatagramProtocol != other.fIpDatagramProtocol) {
599 return false;
600 }
601 if (fMoreFragmentFlag != other.fMoreFragmentFlag) {
602 return false;
603 }
604 if (!Arrays.equals(fOptions, other.fOptions)) {
605 return false;
606 }
607 final ByteBuffer payload = fPayload;
608 if (payload != null) {
609 if (!payload.equals(other.fPayload)) {
610 return false;
611 }
612 } else {
613 if (other.fPayload != null) {
614 return false;
615 }
616 }
617 if (fReservedFlag != other.fReservedFlag) {
618 return false;
619 }
620 if (!Arrays.equals(fSourceIpAddress, other.fSourceIpAddress)) {
621 return false;
622 }
623 if (fTimeToLive != other.fTimeToLive) {
624 return false;
625 }
626 if (fTotalLength != other.fTotalLength) {
627 return false;
628 }
629 if (fVersion != other.fVersion) {
630 return false;
631 }
632 return true;
633 }
634
635 }
This page took 0.049095 seconds and 5 git commands to generate.