Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions pcap4j-core/src/main/java/org/pcap4j/util/IpV6Helper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*_##########################################################################
_##
_## Copyright (C) 2012 Pcap4J.org
_##
_##########################################################################
*/

package org.pcap4j.util;

import java.util.Comparator;
import java.util.List;
import org.pcap4j.packet.*;
import org.pcap4j.packet.factory.PacketFactories;
import org.pcap4j.packet.namednumber.IpNumber;

public final class IpV6Helper {
private static final Comparator<IpV6Packet> comparator = new ComparatorImpl();

private IpV6Helper() {}

/**
* @param ipV6Packet fragmented ivp6 packet
* @return payload length of the fragmented packet
*/
private static int computePayloadLength(IpV6Packet ipV6Packet) {
return ipV6Packet.getHeader().getPayloadLength() - computeExtHeaderSizes(ipV6Packet);
}

private static int computeExtHeaderSizes(Packet packet) {
Packet payload = packet.getPayload();
if (payload instanceof IpV6ExtOptionsPacket) {
IpV6ExtOptionsPacket ipV6ExtOptionsPacket = (IpV6ExtOptionsPacket) payload;
return ((ipV6ExtOptionsPacket.getHeader().getHdrExtLenAsInt() + 1) * 8)
+ computeExtHeaderSizes(payload);
} else if (payload instanceof IpV6ExtFragmentPacket) {
IpV6ExtFragmentPacket ipV6ExtFragmentPacket = (IpV6ExtFragmentPacket) payload;
return (ipV6ExtFragmentPacket.getHeader().length());
} else if (payload instanceof IpV6ExtRoutingPacket) {
IpV6ExtRoutingPacket ipV6ExtRoutingPacket = (IpV6ExtRoutingPacket) payload;
return ((ipV6ExtRoutingPacket.getHeader().getHdrExtLenAsInt() + 1) * 8)
+ computeExtHeaderSizes(payload);
} else {
throw new IllegalArgumentException("Can't find IpV6 fragment packet: " + packet);
}
}

/**
* @param outerOfFragment builder of packet which is previous for ext. fragment header
* @param ipNumber new ip number for the packet
*/
private static void fixIpNumber(Packet.Builder outerOfFragment, IpNumber ipNumber) {
if (outerOfFragment instanceof IpV6Packet.Builder) {
IpV6Packet.Builder builder = (IpV6Packet.Builder) outerOfFragment;
builder.nextHeader(ipNumber);
} else if (outerOfFragment instanceof IpV6ExtOptionsPacket.Builder) {
IpV6ExtOptionsPacket.Builder builder = (IpV6ExtOptionsPacket.Builder) outerOfFragment;
builder.nextHeader(ipNumber);
} else if (outerOfFragment instanceof IpV6ExtRoutingPacket.Builder) {
IpV6ExtRoutingPacket.Builder builder = (IpV6ExtRoutingPacket.Builder) outerOfFragment;
builder.nextHeader(ipNumber);
} else {
throw new IllegalArgumentException("Can't defragment, unexpected header: " + outerOfFragment);
}
}

/**
* @param list list
* @return a defragmented packet.
*/
public static IpV6Packet defragment(List<IpV6Packet> list) {
list.sort(comparator);
IpV6Packet lastPacket = list.get(list.size() - 1);
IpV6ExtFragmentPacket ipV6LastFragmentPacket = lastPacket.get(IpV6ExtFragmentPacket.class);

int payloadTotalLength =
ipV6LastFragmentPacket.getHeader().getFragmentOffset() * 8
+ computePayloadLength(lastPacket);

if (payloadTotalLength <= 0) {
throw new IllegalArgumentException("Can't defragment: " + list);
}

final byte[] defragmentedPayload = new byte[payloadTotalLength];
int destPos = 0;
try {
for (IpV6Packet p : list) {
IpV6ExtFragmentPacket fragmentPacket = p.get(IpV6ExtFragmentPacket.class);
byte[] rawPayload = fragmentPacket.getPayload().getRawData();
System.arraycopy(rawPayload, 0, defragmentedPayload, destPos, rawPayload.length);
destPos += rawPayload.length;
}
} catch (Throwable e) {
throw new IllegalArgumentException("Can't defragment: " + list, e);
}

IpV6Packet firstPacket = list.get(0);
IpV6ExtFragmentPacket ipV6FirstFragmentPacket = firstPacket.get(IpV6ExtFragmentPacket.class);
IpV6Packet.Builder builder = firstPacket.getBuilder();
Packet.Builder outerOfFragmentb = builder.getOuterOf(IpV6ExtFragmentPacket.Builder.class);
outerOfFragmentb.payloadBuilder(
new SimpleBuilder(
PacketFactories.getFactory(Packet.class, IpNumber.class)
.newInstance(
defragmentedPayload,
0,
defragmentedPayload.length,
ipV6FirstFragmentPacket.getHeader().getNextHeader())));
fixIpNumber(outerOfFragmentb, ipV6FirstFragmentPacket.getHeader().getNextHeader());
builder.correctLengthAtBuild(true);
return builder.build();
}

private static final class ComparatorImpl implements Comparator<IpV6Packet> {

@Override
public int compare(IpV6Packet p1, IpV6Packet p2) {
IpV6ExtFragmentPacket fp1 = p1.get(IpV6ExtFragmentPacket.class);
IpV6ExtFragmentPacket fp2 = p2.get(IpV6ExtFragmentPacket.class);

if (fp1 == null) {
throw new IllegalArgumentException("Can't defragment: " + p1);
}

if (fp2 == null) {
throw new IllegalArgumentException("Can't defragment: " + p2);
}

return fp1.getHeader().getFragmentOffset() - fp2.getHeader().getFragmentOffset();
}
}
}
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
/*_##########################################################################
_##
_## Copyright (C) 2012 Pcap4J.org
_##
_##########################################################################
*/

package org.pcap4j.test.util;

import static org.junit.Assert.*;

import java.io.EOFException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.util.concurrent.TimeoutException;
import org.junit.Test;
import org.pcap4j.core.PcapHandle;
import org.pcap4j.core.Pcaps;
import org.pcap4j.packet.*;
import org.pcap4j.packet.namednumber.*;
import org.pcap4j.util.IpV6Helper;
import org.pcap4j.util.MacAddress;

@SuppressWarnings("javadoc")
public class IpV6HelperTest {
private static final String PCAP_FILE_KEY = IpV6HelperTest.class.getName() + ".pcapFile";
private static final String PCAP_FILE =
System.getProperty(
PCAP_FILE_KEY,
"src/test/resources/org/pcap4j/test/core/"
+ IpV6HelperTest.class.getSimpleName()
+ ".pcap");

enum ExtHeader {
DESTINATION,
ROUTING,
NO_HEADER
};

private EthernetPacket getPacket(boolean fragmented) throws UnknownHostException {
UnknownPacket.Builder unknownb = new UnknownPacket.Builder();
unknownb.rawData(new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07});

Inet6Address srcIp = (Inet6Address) InetAddress.getByName("2001:db8::3:2:1");
Inet6Address dstIp = (Inet6Address) InetAddress.getByName("2001:db8::3:2:2");

UdpPacket.Builder udpb = new UdpPacket.Builder();
udpb.srcPort(UdpPort.SNMP_TRAP)
.dstPort(UdpPort.getInstance((short) 0))
.payloadBuilder(unknownb)
.correctChecksumAtBuild(true)
.correctLengthAtBuild(true)
.srcAddr(srcIp)
.dstAddr(dstIp);

IpV6ExtFragmentPacket.Builder fragHeadb = new IpV6ExtFragmentPacket.Builder();
fragHeadb
.fragmentOffset((short) 0)
.identification(123)
.nextHeader(IpNumber.UDP)
.payloadBuilder(udpb);

IpV6Packet.Builder ipv6b = new IpV6Packet.Builder();
ipv6b
.version(IpVersion.IPV6)
.hopLimit((byte) 100)
.trafficClass(IpV6SimpleTrafficClass.newInstance((byte) 0x12))
.flowLabel(IpV6SimpleFlowLabel.newInstance(0x12345))
.nextHeader(fragmented ? IpNumber.IPV6_FRAG : IpNumber.UDP)
.srcAddr(srcIp)
.dstAddr(dstIp)
.payloadBuilder(fragmented ? fragHeadb : udpb)
.correctLengthAtBuild(true);

EthernetPacket.Builder eb = new EthernetPacket.Builder();
eb.dstAddr(MacAddress.getByName("fe:00:00:00:00:02"))
.srcAddr(MacAddress.getByName("fe:00:00:00:00:01"))
.type(EtherType.IPV6)
.payloadBuilder(ipv6b)
.paddingAtBuild(true);

return eb.build();
}

private Packet addExtRoutingHeader(Packet packet, boolean isFragmented)
throws IllegalRawDataException, UnknownHostException {

IpV6ExtRoutingPacket.Builder ipV6ExtRoutingPacketb = new IpV6ExtRoutingPacket.Builder();
ipV6ExtRoutingPacketb
.nextHeader(isFragmented ? IpNumber.IPV6_FRAG : IpNumber.UDP)
.correctLengthAtBuild(true)
.routingType(IpV6RoutingType.NIMROD)
.segmentsLeft((byte) 2)
.data(
new IpV6RoutingSourceRouteData(
0,
new ArrayList<Inet6Address>(
Arrays.asList(
new Inet6Address[] {
(Inet6Address) InetAddress.getByName("2200::210:2:0:0:4")
}))))
.payloadBuilder(
isFragmented
? packet.get(IpV6ExtFragmentPacket.class).getBuilder()
: packet.get(UdpPacket.class).getBuilder());

Packet.Builder packetb = packet.getBuilder();
packetb
.get(IpV6Packet.Builder.class)
.correctLengthAtBuild(true)
.payloadBuilder(ipV6ExtRoutingPacketb)
.nextHeader(IpNumber.IPV6_ROUTE);

return packetb.build();
}

private Packet addExtDestinationHeader(Packet packet, boolean isFragmented)
throws IllegalRawDataException, UnknownHostException {
IpV6ExtDestinationOptionsPacket.Builder ipV6ExtDestinationOptionsPacketb =
new IpV6ExtDestinationOptionsPacket.Builder();
ipV6ExtDestinationOptionsPacketb
.nextHeader(isFragmented ? IpNumber.IPV6_FRAG : IpNumber.UDP)
.correctLengthAtBuild(true)
.options(
new ArrayList<IpV6ExtOptionsPacket.IpV6Option>(
Arrays.asList(
new IpV6ExtOptionsPacket.IpV6Option[] {
new IpV6PadNOption.Builder()
.correctLengthAtBuild(true)
.data(new byte[] {0, 0, 0, 0})
.build()
})))
.payloadBuilder(
isFragmented
? packet.get(IpV6ExtFragmentPacket.class).getBuilder()
: packet.get(UdpPacket.class).getBuilder());

Packet.Builder packetb = packet.getBuilder();
packetb
.get(IpV6Packet.Builder.class)
.correctLengthAtBuild(true)
.payloadBuilder(ipV6ExtDestinationOptionsPacketb)
.nextHeader(IpNumber.IPV6_ROUTE);

return packetb.build();
}

@Test(expected = IllegalArgumentException.class)
public void twoNoFragmentedPackets() throws UnknownHostException {
List<IpV6Packet> ipV6Packets = new ArrayList<IpV6Packet>();
IpV6Packet ipV6Packet = getPacket(false).get(IpV6Packet.class);
ipV6Packets.add(ipV6Packet);
ipV6Packets.add(ipV6Packet);
IpV6Helper.defragment(ipV6Packets);
}

@Test(expected = IllegalArgumentException.class)
public void oneNoFragmentedPacket() throws UnknownHostException {
List<IpV6Packet> ipV6Packets = new ArrayList<IpV6Packet>();
ipV6Packets.add(getPacket(true).get(IpV6Packet.class));
ipV6Packets.add(getPacket(false).get(IpV6Packet.class));
IpV6Helper.defragment(ipV6Packets);
}

private void testDefragment(ExtHeader extHeader) throws Exception {
EthernetPacket expectedPacket;
if (extHeader == ExtHeader.ROUTING) {
expectedPacket = (EthernetPacket) addExtRoutingHeader(getPacket(false), false);
} else if (extHeader == ExtHeader.DESTINATION) {
expectedPacket = (EthernetPacket) addExtDestinationHeader(getPacket(false), false);
} else {
expectedPacket = getPacket(false);
}

PcapHandle handle = Pcaps.openOffline(PCAP_FILE);
List<IpV6Packet> ipV6Packets = new ArrayList<IpV6Packet>();
Packet firstPacket = null;

while (true) {
try {
Packet packet;
if (extHeader == ExtHeader.ROUTING) {
packet = addExtRoutingHeader(handle.getNextPacketEx(), true);
} else if (extHeader == ExtHeader.DESTINATION) {
packet = addExtDestinationHeader(handle.getNextPacketEx(), true);
} else {
packet = handle.getNextPacketEx();
}
if (firstPacket == null) {
firstPacket = packet;
}
ipV6Packets.add(packet.get(IpV6Packet.class));
} catch (TimeoutException e) {
continue;
} catch (EOFException e) {
break;
}
}
handle.close();

Collections.shuffle(ipV6Packets);

IpV6Packet defragmentedIpV6Packet = IpV6Helper.defragment(ipV6Packets);
Packet.Builder actualb = firstPacket.getBuilder();
actualb
.getOuterOf(IpV6Packet.Builder.class)
.payloadBuilder(new SimpleBuilder(defragmentedIpV6Packet));

assertEquals(expectedPacket, actualb.build());
}

@Test
public void testDefragmentWithRoutingHeader() throws Exception {
testDefragment(ExtHeader.ROUTING);
}

@Test
public void testDefragmentWithoutExtHeaders() throws Exception {
testDefragment(ExtHeader.NO_HEADER);
}

@Test
public void testDefragmentWithDestinationExtHeaders() throws Exception {
testDefragment(ExtHeader.DESTINATION);
}
}