Improve the resiliency of the packet deserialization code.
Packet deserializers now check for malformed input while reading the byte
stream. Deserializers are re-implemented as functions that take a byte array
and return a packet object. The old IPacket.deserialize(...) methods have been
deprecated with the goal of eventually moving to immutable packet objects.
Unit tests have been implemented for all Deserializer functions.
ONOS-1589
Change-Id: I9073d5e6e7991e15d43830cfd810989256b71c56
diff --git a/utils/misc/src/main/java/org/onlab/packet/TCP.java b/utils/misc/src/main/java/org/onlab/packet/TCP.java
index 3b92c83..b13b53c 100644
--- a/utils/misc/src/main/java/org/onlab/packet/TCP.java
+++ b/utils/misc/src/main/java/org/onlab/packet/TCP.java
@@ -20,11 +20,16 @@
import java.nio.ByteBuffer;
+import static org.onlab.packet.PacketUtils.*;
+
/**
* Implements TCP packet format.
*/
public class TCP extends BasePacket {
+
+ private static final short TCP_HEADER_LENGTH = 20;
+
protected short sourcePort;
protected short destinationPort;
protected int sequence;
@@ -339,6 +344,40 @@
return data;
}
+ @Override
+ public IPacket deserialize(final byte[] data, final int offset,
+ final int length) {
+ final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+ this.sourcePort = bb.getShort();
+ this.destinationPort = bb.getShort();
+ this.sequence = bb.getInt();
+ this.acknowledge = bb.getInt();
+ this.flags = bb.getShort();
+ this.dataOffset = (byte) (this.flags >> 12 & 0xf);
+ this.flags = (short) (this.flags & 0x1ff);
+ this.windowSize = bb.getShort();
+ this.checksum = bb.getShort();
+ this.urgentPointer = bb.getShort();
+ if (this.dataOffset > 5) {
+ int optLength = (this.dataOffset << 2) - 20;
+ if (bb.limit() < bb.position() + optLength) {
+ optLength = bb.limit() - bb.position();
+ }
+ try {
+ this.options = new byte[optLength];
+ bb.get(this.options, 0, optLength);
+ } catch (final IndexOutOfBoundsException e) {
+ this.options = null;
+ }
+ }
+
+ this.payload = new Data();
+ this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
+ - bb.position());
+ this.payload.setParent(this);
+ return this;
+ }
+
/*
* (non-Javadoc)
*
@@ -384,37 +423,39 @@
&& (this.dataOffset == 5 || this.options.equals(other.options));
}
- @Override
- public IPacket deserialize(final byte[] data, final int offset,
- final int length) {
- final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
- this.sourcePort = bb.getShort();
- this.destinationPort = bb.getShort();
- this.sequence = bb.getInt();
- this.acknowledge = bb.getInt();
- this.flags = bb.getShort();
- this.dataOffset = (byte) (this.flags >> 12 & 0xf);
- this.flags = (short) (this.flags & 0x1ff);
- this.windowSize = bb.getShort();
- this.checksum = bb.getShort();
- this.urgentPointer = bb.getShort();
- if (this.dataOffset > 5) {
- int optLength = (this.dataOffset << 2) - 20;
- if (bb.limit() < bb.position() + optLength) {
- optLength = bb.limit() - bb.position();
- }
- try {
- this.options = new byte[optLength];
- bb.get(this.options, 0, optLength);
- } catch (final IndexOutOfBoundsException e) {
- this.options = null;
- }
- }
+ /**
+ * Deserializer function for TCP packets.
+ *
+ * @return deserializer function
+ */
+ public static Deserializer<TCP> deserializer() {
+ return (data, offset, length) -> {
+ checkInput(data, offset, length, TCP_HEADER_LENGTH);
- this.payload = new Data();
- this.payload = this.payload.deserialize(data, bb.position(), bb.limit()
- - bb.position());
- this.payload.setParent(this);
- return this;
+ TCP tcp = new TCP();
+
+ final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+ tcp.sourcePort = bb.getShort();
+ tcp.destinationPort = bb.getShort();
+ tcp.sequence = bb.getInt();
+ tcp.acknowledge = bb.getInt();
+ tcp.flags = bb.getShort();
+ tcp.dataOffset = (byte) (tcp.flags >> 12 & 0xf);
+ tcp.flags = (short) (tcp.flags & 0x1ff);
+ tcp.windowSize = bb.getShort();
+ tcp.checksum = bb.getShort();
+ tcp.urgentPointer = bb.getShort();
+ if (tcp.dataOffset > 5) {
+ int optLength = (tcp.dataOffset << 2) - 20;
+ checkHeaderLength(length, TCP_HEADER_LENGTH + tcp.dataOffset);
+ tcp.options = new byte[optLength];
+ bb.get(tcp.options, 0, optLength);
+ }
+
+ tcp.payload = Data.deserializer()
+ .deserialize(data, bb.position(), bb.limit() - bb.position());
+ tcp.payload.setParent(tcp);
+ return tcp;
+ };
}
}