Skip to content

Commit

Permalink
Merge branch 'michaelkoetter-udp-checksum'
Browse files Browse the repository at this point in the history
  • Loading branch information
kaitoy committed May 20, 2017
1 parent 6617e0d commit 62fce7a
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 134 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Future
* [Issues#76](https://github.com/kaitoy/pcap4j/issues/76): NullPointerException when dissecting an ICMP error packet.
* [Issues#80](https://github.com/kaitoy/pcap4j/issues/80): Intermittent SIGSEGV in finalizer for BpfProgram.
* [Issues#88](https://github.com/kaitoy/pcap4j/issues/88): pcap4-core and pcap4j-packetfactory-static both ship org.pcap4j.packet.factory.StaticUnknownPacketFactory
* [Issues#94](https://github.com/kaitoy/pcap4j/issues/94): UdpPacket.hasValidChecksum is broken for checksum 0xFFFF.

### Other Changes ###
* [PR#78](https://github.com/kaitoy/pcap4j/pull/78) [Issues#75](https://github.com/kaitoy/pcap4j/issues/75): Change PropertiesLoader to log with INFO instead of WARN when it returns the default value.
Expand Down
21 changes: 2 additions & 19 deletions pcap4j-core/src/main/java/org/pcap4j/packet/AbstractPacket.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*_##########################################################################
_##
_## Copyright (C) 2011-2014 Pcap4J.org
_## Copyright (C) 2011-2017 Pcap4J.org
_##
_##########################################################################
*/
Expand Down Expand Up @@ -499,24 +499,7 @@ public int length() {
* @return a raw data built
*/
protected byte[] buildRawData() {
List<byte[]> rawFields = getRawFields();

int length = 0;
for (byte[] rawField: rawFields) {
length += rawField.length;
}

byte[] rawData = new byte[length];
int destPos = 0;
for (byte[] rawField: rawFields) {
System.arraycopy(
rawField, 0,
rawData, destPos, rawField.length
);
destPos += rawField.length;
}

return rawData;
return ByteArrays.concatenate(getRawFields());
}

/**
Expand Down
46 changes: 24 additions & 22 deletions pcap4j-core/src/main/java/org/pcap4j/packet/IcmpV4CommonPacket.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*_##########################################################################
_##
_## Copyright (C) 2012-2014 Pcap4J.org
_## Copyright (C) 2012-2017 Pcap4J.org
_##
_##########################################################################
*/
Expand Down Expand Up @@ -105,17 +105,17 @@ public Builder getBuilder() {
* false otherwise.
*/
public boolean hasValidChecksum(boolean acceptZero) {
if (header.checksum == 0) {
if (acceptZero) { return true; }
else { return false; }
byte[] payloadData = payload != null ? payload.getRawData() : new byte[0];
short calculatedChecksum = header.calcChecksum(header.getRawData(), payloadData);
if (calculatedChecksum == 0) {
return true;
}

if (payload != null) {
return header.calcChecksum(payload.getRawData()) == header.checksum;
}
else {
return header.calcChecksum(new byte[0]) == header.checksum;
if (header.checksum == 0 && acceptZero) {
return true;
}

return false;
}

/**
Expand Down Expand Up @@ -270,7 +270,7 @@ private IcmpV4CommonHeader(Builder builder, byte[] payload) {

if (builder.correctChecksumAtBuild) {
if (PacketPropertiesLoader.getInstance().icmpV4CalcChecksum()) {
this.checksum = calcChecksum(payload);
this.checksum = calcChecksum(buildRawData(true), payload);
}
else {
this.checksum = (short)0;
Expand All @@ -281,7 +281,7 @@ private IcmpV4CommonHeader(Builder builder, byte[] payload) {
}
}

private short calcChecksum(byte[] payload) {
private short calcChecksum(byte[] header, byte[] payload) {
byte[] data;
int packetLength = payload.length + length();

Expand All @@ -292,18 +292,12 @@ private short calcChecksum(byte[] payload) {
data = new byte[packetLength];
}

// If call getRawData() here, rawData will be cached with
// an invalid checksum in some cases.
// To avoid it, use buildRawData() instead.
System.arraycopy(buildRawData(), 0, data, 0, length());

System.arraycopy(
payload, 0, data, length(), payload.length
header, 0, data, 0, header.length
);
System.arraycopy(
payload, 0, data, header.length, payload.length
);

for (int i = 0; i < CHECKSUM_SIZE; i++) {
data[CHECKSUM_OFFSET + i] = (byte)0;
}

return ByteArrays.calcChecksum(data);
}
Expand Down Expand Up @@ -334,13 +328,21 @@ public short getChecksum() {

@Override
protected List<byte[]> getRawFields() {
return getRawFields(false);
}

private List<byte[]> getRawFields(boolean zeroInsteadOfChecksum) {
List<byte[]> rawFields = new ArrayList<byte[]>();
rawFields.add(ByteArrays.toByteArray(type.value()));
rawFields.add(ByteArrays.toByteArray(code.value()));
rawFields.add(ByteArrays.toByteArray(checksum));
rawFields.add(ByteArrays.toByteArray(zeroInsteadOfChecksum ? (short) 0 : checksum));
return rawFields;
}

private byte[] buildRawData(boolean zeroInsteadOfChecksum) {
return ByteArrays.concatenate(getRawFields(zeroInsteadOfChecksum));
}

@Override
public int length() {
return ICMPV4_COMMON_HEADER_SIZE;
Expand Down
57 changes: 30 additions & 27 deletions pcap4j-core/src/main/java/org/pcap4j/packet/IcmpV6CommonPacket.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*_##########################################################################
_##
_## Copyright (C) 2013-2016 Pcap4J.org
_## Copyright (C) 2013-2017 Pcap4J.org
_##
_##########################################################################
*/
Expand All @@ -15,10 +15,7 @@
import java.util.List;

import org.pcap4j.packet.factory.PacketFactories;
import org.pcap4j.packet.namednumber.IcmpV6Code;
import org.pcap4j.packet.namednumber.IcmpV6Type;
import org.pcap4j.packet.namednumber.IpNumber;
import org.pcap4j.packet.namednumber.IpV6NeighborDiscoveryOptionType;
import org.pcap4j.packet.namednumber.*;
import org.pcap4j.util.ByteArrays;

/**
Expand Down Expand Up @@ -137,19 +134,18 @@ public boolean hasValidChecksum(
throw new IllegalArgumentException(sb.toString());
}

if (header.checksum == 0) {
if (acceptZero) { return true; }
else { return false; }
byte[] payloadData = payload != null ? payload.getRawData() : new byte[0];
short calculatedChecksum
= header.calcChecksum(srcAddr, dstAddr, header.getRawData(), payloadData);
if (calculatedChecksum == 0) {
return true;
}

if (payload != null) {
return header.calcChecksum(srcAddr, dstAddr, payload.getRawData())
== header.checksum;
}
else {
return header.calcChecksum(srcAddr, dstAddr, new byte[0])
== header.checksum;
if (header.checksum == 0 && acceptZero) {
return true;
}

return false;
}

/**
Expand Down Expand Up @@ -330,7 +326,13 @@ private IcmpV6CommonHeader(Builder builder, byte[] payload) {

if (builder.correctChecksumAtBuild) {
if (PacketPropertiesLoader.getInstance().icmpV6CalcChecksum()) {
this.checksum = calcChecksum(builder.srcAddr, builder.dstAddr, payload);
this.checksum
= calcChecksum(
builder.srcAddr,
builder.dstAddr,
buildRawData(true),
payload
);
}
else {
this.checksum = (short)0;
Expand All @@ -342,7 +344,7 @@ private IcmpV6CommonHeader(Builder builder, byte[] payload) {
}

private short calcChecksum(
Inet6Address srcAddr, Inet6Address dstAddr, byte[] payload
Inet6Address srcAddr, Inet6Address dstAddr, byte[] header, byte[] payload
) {
byte[] data;
int destPos;
Expand All @@ -357,15 +359,8 @@ private short calcChecksum(
destPos = totalLength;
}

// If call getRawData() here, rawData will be cached with
// an invalid checksum in some cases.
// To avoid it, use buildRawData() instead.
System.arraycopy(buildRawData(), 0, data, 0, length());
System.arraycopy(payload, 0, data, length(), payload.length);

for (int i = 0; i < CHECKSUM_SIZE; i++) {
data[CHECKSUM_OFFSET + i] = (byte)0;
}
System.arraycopy(header, 0, data, 0, header.length);
System.arraycopy(payload, 0, data, header.length, payload.length);

// pseudo header
System.arraycopy(
Expand Down Expand Up @@ -420,13 +415,21 @@ public short getChecksum() {

@Override
protected List<byte[]> getRawFields() {
return getRawFields(false);
}

private List<byte[]> getRawFields(boolean zeroInsteadOfChecksum) {
List<byte[]> rawFields = new ArrayList<byte[]>();
rawFields.add(ByteArrays.toByteArray(type.value()));
rawFields.add(ByteArrays.toByteArray(code.value()));
rawFields.add(ByteArrays.toByteArray(checksum));
rawFields.add(ByteArrays.toByteArray(zeroInsteadOfChecksum ? (short) 0 : checksum));
return rawFields;
}

private byte[] buildRawData(boolean zeroInsteadOfChecksum) {
return ByteArrays.concatenate(getRawFields(zeroInsteadOfChecksum));
}

@Override
public int length() {
return ICMPV6_COMMON_HEADER_SIZE;
Expand Down
42 changes: 23 additions & 19 deletions pcap4j-core/src/main/java/org/pcap4j/packet/IpV4Packet.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*_##########################################################################
_##
_## Copyright (C) 2011-2016 Pcap4J.org
_## Copyright (C) 2011-2017 Pcap4J.org
_##
_##########################################################################
*/
Expand Down Expand Up @@ -662,7 +662,7 @@ private IpV4Header(Builder builder, Packet payload) {

if (builder.correctChecksumAtBuild) {
if (PacketPropertiesLoader.getInstance().ipV4CalcChecksum()) {
headerChecksum = calcHeaderChecksum();
headerChecksum = calcHeaderChecksum(true);
}
else {
headerChecksum = (short)0;
Expand All @@ -673,17 +673,8 @@ private IpV4Header(Builder builder, Packet payload) {
}
}

private short calcHeaderChecksum() {
// If call getRawData() here, rawData will be cached with
// an invalid checksum in some cases.
// To avoid it, use buildRawData() instead.
byte[] data = buildRawData();

for (int i = 0; i < HEADER_CHECKSUM_SIZE; i++) {
data[HEADER_CHECKSUM_OFFSET + i] = (byte)0;
}

return ByteArrays.calcChecksum(data);
private short calcHeaderChecksum(boolean zeroInsteadOfChecksum) {
return ByteArrays.calcChecksum(buildRawData(zeroInsteadOfChecksum));
}

@Override
Expand Down Expand Up @@ -840,18 +831,27 @@ public byte[] getPadding() {
*
* @param acceptZero acceptZero
* @return true if the packet represented by this object has a valid checksum;
* false otherwise.
* false otherwise.
*/
public boolean hasValidChecksum(boolean acceptZero) {
if (headerChecksum == 0) {
if (acceptZero) { return true; }
else { return false; }
short calculatedChecksum = calcHeaderChecksum(false);
if (calculatedChecksum == 0) {
return true;
}

if (headerChecksum == 0 && acceptZero) {
return true;
}
return calcHeaderChecksum() == headerChecksum;

return false;
}

@Override
protected List<byte[]> getRawFields() {
return getRawFields(false);
}

private List<byte[]> getRawFields(boolean zeroInsteadOfChecksum) {
byte flags = 0;
if (moreFragmentFlag) { flags = (byte)1; }
if (dontFragmentFlag) { flags = (byte)(flags | 2); }
Expand All @@ -865,7 +865,7 @@ protected List<byte[]> getRawFields() {
rawFields.add(ByteArrays.toByteArray((short)((flags << 13) | fragmentOffset)));
rawFields.add(ByteArrays.toByteArray(ttl));
rawFields.add(ByteArrays.toByteArray(protocol.value()));
rawFields.add(ByteArrays.toByteArray(headerChecksum));
rawFields.add(ByteArrays.toByteArray(zeroInsteadOfChecksum ? (short) 0 : headerChecksum));
rawFields.add(ByteArrays.toByteArray(srcAddr));
rawFields.add(ByteArrays.toByteArray(dstAddr));
for (IpV4Option o: options) {
Expand All @@ -875,6 +875,10 @@ protected List<byte[]> getRawFields() {
return rawFields;
}

private byte[] buildRawData(boolean zeroInsteadOfChecksum) {
return ByteArrays.concatenate(getRawFields(zeroInsteadOfChecksum));
}

private int measureLengthWithoutPadding() {
int len = 0;
for (IpV4Option o: options) {
Expand Down
Loading

0 comments on commit 62fce7a

Please sign in to comment.