package net.decix.jipfix.generator;
import java.io.IOException;
import java.math.BigInteger;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import net.decix.jipfix.header.InformationElement;
import net.decix.jipfix.header.L2IPDataRecord;
import net.decix.jipfix.header.MessageHeader;
import net.decix.jipfix.header.OptionTemplateRecord;
import net.decix.jipfix.header.SamplingDataRecord;
import net.decix.jipfix.header.SetHeader;
import net.decix.jipfix.header.TemplateRecord;
import net.decix.util.HeaderBytesException;
import net.decix.util.MacAddress;
import net.decix.util.UtilityException;
import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.savarese.vserv.tcpip.IPPacket;
import org.savarese.vserv.tcpip.OctetConverter;
import org.savarese.vserv.tcpip.UDPPacket;
import com.savarese.rocksaw.net.RawSocket;
public class IPFIXGenerator {
public static void main(String args[]) {
Option ingressPhysicalInterfaceID = OptionBuilder.withArgName("id").hasArgs().withDescription("ingress physical interface identifier").create("ingressPhysicalInterfaceID");
Option egressPhysicalInterfaceID = OptionBuilder.withArgName("id").hasArgs().withDescription("egress physical interface identifer").create("egressPhysicalInterfaceID");
Option innerVLAN = OptionBuilder.withArgName("vlan").hasArgs().withDescription("inner VLAN").create("innerVLAN");
Option outerVLAN = OptionBuilder.withArgName("vlan").hasArgs().withDescription("outer VLAN").create("outerVLAN");
Option srcMAC = OptionBuilder.withArgName("mac").hasArgs().withDescription("source MAC address").create("srcMAC");
Option destMAC = OptionBuilder.withArgName("mac").hasArgs().withDescription("destination MAC address").create("destMAC");
Option ipVersion = OptionBuilder.withArgName("version").hasArgs().withDescription("IP version").create("ipVersion");
Option transportProtocol = OptionBuilder.withArgName("protocol").hasArgs().withDescription("transport layer protocol").create("transportProtocol");
Option srcIPv4 = OptionBuilder.withArgName("ipv4").hasArgs().withDescription("source IPv4 address").create("srcIPv4");
Option destIPv4 = OptionBuilder.withArgName("ipv4").hasArgs().withDescription("destination IPv4 address").create("destIPv4");
Option srcIPv6 = OptionBuilder.withArgName("ipv6").hasArgs().withDescription("source IPv6 address").create("srcIPv6");
Option destIPv6 = OptionBuilder.withArgName("ipv6").hasArgs().withDescription("destination IPv6 address").create("destIPv6");
Option srcPort = OptionBuilder.withArgName("port").hasArgs().withDescription("source port").create("srcPort");
Option destPort = OptionBuilder.withArgName("port").hasArgs().withDescription("destination port").create("destPort");
Option icmpType = OptionBuilder.withArgName("type").hasArgs().withDescription("ICMP type").create("icmpType");
Option packets = OptionBuilder.withArgName("packets").hasArgs().withDescription("packets (default: 1)").create("packets");
Option octets = OptionBuilder.withArgName("octets").hasArgs().withDescription("octets in Bytes (default: 100000)").create("octets");
Option dataRate = OptionBuilder.withArgName("rate").hasArgs().withDescription("data rate in MBit/s (default: 1 MBit/s)").create("dataRate");
Option samplingRate = OptionBuilder.withArgName("rate").hasArgs().withDescription("sampling rate (default: 10000)").create("samplingRate");
Option collectorIPv4 = OptionBuilder.withArgName("ipv4").hasArgs().withDescription("IPFIX collector IPv4 address (required)").create("collectorIPv4");
Option collectorPort = OptionBuilder.withArgName("port").hasArgs().withDescription("IPFIX collector UDP port (default: 2601)").create("collectorPort");
Option exporterIPv4 = OptionBuilder.withArgName("ipv4").hasArgs().withDescription("IPFIX exporter (spoofed) IPv4 address").create("exporterIPv4");
Option exporterPort = OptionBuilder.withArgName("port").hasArgs().withDescription("IPFIX exporter UDP port (default: 2601)").create("exporterPort");
Option debug = OptionBuilder.withArgName("debug").withDescription("enable debug").create("debug");
Options options = new Options();
options.addOption(ingressPhysicalInterfaceID);
options.addOption(egressPhysicalInterfaceID);
options.addOption(innerVLAN);
options.addOption(outerVLAN);
options.addOption(srcMAC);
options.addOption(destMAC);
options.addOption(ipVersion);
options.addOption(transportProtocol);
options.addOption(srcIPv4);
options.addOption(destIPv4);
options.addOption(srcIPv6);
options.addOption(destIPv6);
options.addOption(srcPort);
options.addOption(destPort);
options.addOption(icmpType);
options.addOption(srcIPv4);
options.addOption(packets);
options.addOption(octets);
options.addOption(dataRate);
options.addOption(samplingRate);
options.addOption(collectorIPv4);
options.addOption(collectorPort);
options.addOption(exporterIPv4);
options.addOption(exporterPort);
options.addOption(debug);
CommandLineParser parser = new BasicParser();
try {
CommandLine line = parser.parse(options, args);
if (!line.hasOption("collectorIPv4")) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp( "IPFIXGenerator", options );
System.exit(0);
}
Random random = new Random();
// physical interface IDs
int ingressPhysicalInterfaceIDValue = random.nextInt();
while (ingressPhysicalInterfaceIDValue < 0) ingressPhysicalInterfaceIDValue = random.nextInt();
if (line.hasOption("ingressPhysicalInterfaceID")) {
ingressPhysicalInterfaceIDValue = Integer.parseInt(line.getOptionValue("ingressPhysicalInterfaceID"));
}
int egressPhysicalInterfaceIDValue = random.nextInt();
while (egressPhysicalInterfaceIDValue < 0) egressPhysicalInterfaceIDValue = random.nextInt();
if (line.hasOption("egressPhysicalInterfaceID")) {
egressPhysicalInterfaceIDValue = Integer.parseInt(line.getOptionValue("egressPhysicalInterfaceID"));
}
// VLANs
int innerVLANValue = random.nextInt(4096);
if (line.hasOption("innerVLAN")) {
innerVLANValue = Integer.parseInt(line.getOptionValue("innerVLAN"));
}
int outerVLANValue = random.nextInt(4096);
if (line.hasOption("outerVLAN")) {
outerVLANValue = Integer.parseInt(line.getOptionValue("outerVLAN"));
}
// MACs
byte[] mac = new byte[6];
random.nextBytes(mac);
MacAddress srcMACValue = new MacAddress(mac);
if (line.hasOption("srcMAC")) {
srcMACValue = new MacAddress(line.getOptionValue("srcMAC"));
}
random.nextBytes(mac);
MacAddress destMACValue = new MacAddress(mac);
if (line.hasOption("destMAC")) {
destMACValue = new MacAddress(line.getOptionValue("destMAC"));
}
// IP version
short ipVersionValue = (short) (random.nextBoolean() ? 4 : 6);
if (line.hasOption("ipVersion")) {
ipVersionValue = Short.parseShort(line.getOptionValue("ipVersion"));
}
// transport protocol
short transportProtocolValue = (short) (random.nextBoolean() ? 6 : 17);
if (line.hasOption("transportProtocol")) {
transportProtocolValue = Short.parseShort(line.getOptionValue("transportProtocol"));
}
// IPv4 address
byte[] addrIPv4 = new byte[4];
random.nextBytes(addrIPv4);
Inet4Address srcIPv4Value = (Inet4Address) Inet4Address.getByAddress(addrIPv4);
if (line.hasOption("srcIPv4")) {
srcIPv4Value = (Inet4Address) Inet4Address.getByName(line.getOptionValue("srcIPv4"));
}
random.nextBytes(addrIPv4);
Inet4Address destIPv4Value = (Inet4Address) Inet4Address.getByAddress(addrIPv4);
if (line.hasOption("destIPv4")) {
destIPv4Value = (Inet4Address) Inet4Address.getByName(line.getOptionValue("destIPv4"));
}
// IPv6 address
byte[] addrIPv6 = new byte[16];
random.nextBytes(addrIPv6);
Inet6Address srcIPv6Value = (Inet6Address) Inet6Address.getByAddress(addrIPv6);
if (line.hasOption("srcIPv6")) {
srcIPv6Value = (Inet6Address) Inet6Address.getByName(line.getOptionValue("srcIPv6"));
}
random.nextBytes(addrIPv6);
Inet6Address destIPv6Value = (Inet6Address) Inet6Address.getByAddress(addrIPv6);
if (line.hasOption("destIPv6")) {
destIPv6Value = (Inet6Address) Inet6Address.getByName(line.getOptionValue("destIPv6"));
}
// ports
int srcPortValue = random.nextInt(65534);
if (line.hasOption("srcPort")) {
srcPortValue = Integer.parseInt(line.getOptionValue("srcPort"));
}
int destPortValue = random.nextInt(65534);
if (line.hasOption("destPort")) {
destPortValue = Integer.parseInt(line.getOptionValue("destPort"));
}
// icmp type
int icmpTypeValue = 0;
if (line.hasOption("icmpType")) {
icmpTypeValue = Integer.parseInt(line.getOptionValue("icmpType"));
}
// packets
int packetsValue = 1;
if (line.hasOption("packets")) {
packetsValue = Integer.parseInt(line.getOptionValue("packets"));
}
// octets
int octetsValue = 100000;
if (line.hasOption("octets")) {
octetsValue = Integer.parseInt(line.getOptionValue("octets"));
}
// data rate
int dataRateValue = 1; // 1 MBit/s
if (line.hasOption("dataRate")) {
dataRateValue = Integer.parseInt(line.getOptionValue("dataRate"));
}
// sampling rate
int samplingRateValue = 10000;
if (line.hasOption("samplingRate")) {
samplingRateValue = Integer.parseInt(line.getOptionValue("samplingRate"));
}
// collector IP and port
InetAddress collectorIPv4Value = null;
if (line.hasOption("collectorIPv4")) {
collectorIPv4Value = InetAddress.getByName(line.getOptionValue("collectorIPv4"));
}
int collectorPortValue = 2601;
if (line.hasOption("collectorPort")) {
collectorPortValue = Integer.parseInt(line.getOptionValue("collectorPort"));
}
// exporter IP and port
InetAddress exporterIPv4Value = null;
if (line.hasOption("exporterIPv4")) {
exporterIPv4Value = InetAddress.getByName(line.getOptionValue("exporterIPv4"));
}
int exporterPortValue = 2601;
if (line.hasOption("exporterPort")) {
collectorPortValue = Integer.parseInt(line.getOptionValue("exporterPort"));
}
// create IPFIX data
//
// Message header
MessageHeader mh = new MessageHeader();
mh.setVersionNumber(10);
mh.setObservationDomainID(67108864);
// Set header for the template
SetHeader shTemplate = new SetHeader();
mh.getSetHeaders().add(shTemplate);
shTemplate.setSetID(2);
TemplateRecord tr = new TemplateRecord();
shTemplate.getTemplateRecords().add(tr);
tr.setTemplateID(306);
tr.setFieldCount(26);
InformationElement iESrcMAC = new InformationElement();
iESrcMAC.setFieldLength(6);
iESrcMAC.setInformationElementID(56);
tr.getInformationElements().add(iESrcMAC);
InformationElement iEDestMAC = new InformationElement();
iEDestMAC.setFieldLength(6);
iEDestMAC.setInformationElementID(80);
tr.getInformationElements().add(iEDestMAC);
InformationElement iEingressPhysicalID = new InformationElement();
iEingressPhysicalID.setFieldLength(4);
iEingressPhysicalID.setInformationElementID(252);
tr.getInformationElements().add(iEingressPhysicalID);
InformationElement iEegressPhysicalID = new InformationElement();
iEegressPhysicalID.setFieldLength(4);
iEegressPhysicalID.setInformationElementID(253);
tr.getInformationElements().add(iEegressPhysicalID);
InformationElement iEdot1qVlandId = new InformationElement();
iEdot1qVlandId.setFieldLength(2);
iEdot1qVlandId.setInformationElementID(243);
tr.getInformationElements().add(iEdot1qVlandId);
InformationElement iEdot1qCVlandId = new InformationElement();
iEdot1qCVlandId.setFieldLength(2);
iEdot1qCVlandId.setInformationElementID(245);
tr.getInformationElements().add(iEdot1qCVlandId);
InformationElement iEPostDot1qVlandId = new InformationElement();
iEPostDot1qVlandId.setFieldLength(2);
iEPostDot1qVlandId.setInformationElementID(255);
tr.getInformationElements().add(iEPostDot1qVlandId);
InformationElement iEPostDot1qCVlandId = new InformationElement();
iEPostDot1qCVlandId.setFieldLength(2);
iEPostDot1qCVlandId.setInformationElementID(254);
tr.getInformationElements().add(iEPostDot1qCVlandId);
InformationElement iEIPv4Src = new InformationElement();
iEIPv4Src.setFieldLength(4);
iEIPv4Src.setInformationElementID(8);
tr.getInformationElements().add(iEIPv4Src);
InformationElement iEIPv4Dest = new InformationElement();
iEIPv4Dest.setFieldLength(4);
iEIPv4Dest.setInformationElementID(12);
tr.getInformationElements().add(iEIPv4Dest);
InformationElement iEIPv6Src = new InformationElement();
iEIPv6Src.setFieldLength(16);
iEIPv6Src.setInformationElementID(27);
tr.getInformationElements().add(iEIPv6Src);
InformationElement iEIPv6Dest = new InformationElement();
iEIPv6Dest.setFieldLength(16);
iEIPv6Dest.setInformationElementID(28);
tr.getInformationElements().add(iEIPv6Dest);
InformationElement iEPkts = new InformationElement();
iEPkts.setFieldLength(4);
iEPkts.setInformationElementID(2);
tr.getInformationElements().add(iEPkts);
InformationElement iEBytes = new InformationElement();
iEBytes.setFieldLength(4);
iEBytes.setInformationElementID(1);
tr.getInformationElements().add(iEBytes);
InformationElement iEFlowStart = new InformationElement();
iEFlowStart.setFieldLength(8);
iEFlowStart.setInformationElementID(152);
tr.getInformationElements().add(iEFlowStart);
InformationElement iEFlowEnd = new InformationElement();
iEFlowEnd.setFieldLength(8);
iEFlowEnd.setInformationElementID(153);
tr.getInformationElements().add(iEFlowEnd);
InformationElement iEPortSrc = new InformationElement();
iEPortSrc.setFieldLength(2);
iEPortSrc.setInformationElementID(7);
tr.getInformationElements().add(iEPortSrc);
InformationElement iEPortDest = new InformationElement();
iEPortDest.setFieldLength(2);
iEPortDest.setInformationElementID(7);
tr.getInformationElements().add(iEPortDest);
InformationElement iETCPFlags = new InformationElement();
iETCPFlags.setFieldLength(1);
iETCPFlags.setInformationElementID(6);
tr.getInformationElements().add(iETCPFlags);
InformationElement iEProtocol = new InformationElement();
iEProtocol.setFieldLength(1);
iEProtocol.setInformationElementID(4);
tr.getInformationElements().add(iEProtocol);
InformationElement iEIPv6OptionHeaders = new InformationElement();
iEIPv6OptionHeaders.setFieldLength(4);
iEIPv6OptionHeaders.setInformationElementID(64);
tr.getInformationElements().add(iEIPv6OptionHeaders);
InformationElement iENextHeaderIPv6 = new InformationElement();
iENextHeaderIPv6.setFieldLength(1);
iENextHeaderIPv6.setInformationElementID(193);
tr.getInformationElements().add(iENextHeaderIPv6);
InformationElement iEFlowLabel = new InformationElement();
iEFlowLabel.setFieldLength(4);
iEFlowLabel.setInformationElementID(31);
tr.getInformationElements().add(iEFlowLabel);
InformationElement iEIPTOS = new InformationElement();
iEIPTOS.setFieldLength(1);
iEIPTOS.setInformationElementID(5);
tr.getInformationElements().add(iEIPTOS);
InformationElement iEIPVersion = new InformationElement();
iEIPVersion.setFieldLength(1);
iEIPVersion.setInformationElementID(60);
tr.getInformationElements().add(iEIPVersion);
InformationElement iEICMPType = new InformationElement();
iEICMPType.setFieldLength(2);
iEICMPType.setInformationElementID(32);
tr.getInformationElements().add(iEICMPType);
// Set header for the template options
SetHeader shTemplateOptions = new SetHeader();
mh.getSetHeaders().add(shTemplateOptions);
shTemplateOptions.setSetID(3);
OptionTemplateRecord otr = new OptionTemplateRecord();
shTemplateOptions.getOptionTemplateRecords().add(otr);
otr.setTemplateID(256);
otr.setScopeFieldCount(1);
otr.setFieldCount(4);
InformationElement iEObservationDomainID = new InformationElement();
iEObservationDomainID.setFieldLength(4);
iEObservationDomainID.setInformationElementID(149);
otr.getInformationElements().add(iEObservationDomainID);
InformationElement iESelectorAlgorithm = new InformationElement();
iESelectorAlgorithm.setFieldLength(2);
iESelectorAlgorithm.setInformationElementID(304);
otr.getInformationElements().add(iESelectorAlgorithm);
InformationElement iESamplingPacketInterval = new InformationElement();
iESamplingPacketInterval.setFieldLength(4);
iESamplingPacketInterval.setInformationElementID(305);
otr.getInformationElements().add(iESamplingPacketInterval);
InformationElement iESamplingPacketSpace = new InformationElement();
iESamplingPacketSpace.setFieldLength(4);
iESamplingPacketSpace.setInformationElementID(306);
otr.getInformationElements().add(iESamplingPacketSpace);
// Set header for the sampling
SetHeader shSampling = new SetHeader();
shSampling.setSetID(256);
mh.getSetHeaders().add(shSampling);
SamplingDataRecord sdr = new SamplingDataRecord();
shSampling.getDataRecords().add(sdr);
sdr.setObservationDomainId(67108864);
sdr.setSelectorAlgorithm(1);
sdr.setSamplingPacketInterval(1);
sdr.setSamplingPacketSpace(samplingRateValue - 1);
// Set header for the L2IP
SetHeader shDataRecord = new SetHeader();
shDataRecord.setSetID(306);
mh.getSetHeaders().add(shDataRecord);
L2IPDataRecord l2ip = new L2IPDataRecord();
shDataRecord.getDataRecords().add(l2ip);
l2ip.setIngressPhysicalInterface(ingressPhysicalInterfaceIDValue);
l2ip.setEgressPhysicalInterface(egressPhysicalInterfaceIDValue);
l2ip.setDot1qVlanId(outerVLANValue);
l2ip.setDot1qCustomerVlanId(innerVLANValue);
l2ip.setSourceMacAddress(srcMACValue);
l2ip.setDestinationMacAddress(destMACValue);
l2ip.setIpVersion(ipVersionValue);
l2ip.setProtocolIdentifier(transportProtocolValue);
if (ipVersionValue == 4) {
l2ip.setSourceIPv4Address(srcIPv4Value);
l2ip.setDestinationIPv4Address(destIPv4Value);
}
if (ipVersionValue == 6) {
l2ip.setSourceIPv6Address(srcIPv6Value);
l2ip.setDestinationIPv6Address(destIPv6Value);
}
l2ip.setSourceTransportPort(srcPortValue);
l2ip.setDestinationTransportPort(destPortValue);
l2ip.setIcmpTypeCodeIPv4(icmpTypeValue);
l2ip.setPacketDeltaCount(packetsValue);
l2ip.setOctetDeltaCount(octetsValue);
// socket handling
RawSocket rawSocket = null;
DatagramSocket datagramSocket = null;
if (exporterIPv4Value != null) {
rawSocket = new RawSocket();
rawSocket.open(RawSocket.PF_INET, RawSocket.getProtocolByName("udp"));
rawSocket.setIPHeaderInclude(true);
} else {
datagramSocket = new DatagramSocket(exporterPortValue);
}
long seqNumber = 0;
while (true) {
// Message header updating
mh.setSequenceNumber(seqNumber);
mh.setExportTime(new Date());
seqNumber++;
// L2IP updating
BigInteger flowStartEnd = BigInteger.valueOf(new Date().getTime());
l2ip.setFlowStartMilliseconds(flowStartEnd);
l2ip.setFlowEndMilliseconds(flowStartEnd);
if (exporterIPv4Value != null) {
byte[] data = new byte[mh.getBytes().length];
UDPPacket udp = new UDPPacket(28 + data.length);
udp.setIPVersion(4);
udp.setIPHeaderLength(5);
udp.setProtocol(IPPacket.PROTOCOL_UDP);
udp.setTTL(5);
udp.setUDPDataByteLength(data.length);
udp.setUDPPacketLength(data.length + 8);
udp.setDestinationPort(collectorPortValue);
udp.setSourcePort(exporterPortValue);
byte[] pktData = new byte[udp.size()];
udp.setDestinationAsWord(OctetConverter.octetsToInt(collectorIPv4Value.getAddress()));
udp.setSourceAsWord(OctetConverter.octetsToInt(exporterIPv4Value.getAddress()));
System.arraycopy(data, 0, pktData, 28, data.length);
udp.setData(pktData);
udp.computeUDPChecksum(true);
udp.computeIPChecksum(true);
udp.getData(pktData);
rawSocket.write(collectorIPv4Value, pktData);
} else {
DatagramPacket dp = new DatagramPacket(mh.getBytes(), mh.getBytes().length, collectorIPv4Value, collectorPortValue);
datagramSocket.send(dp);
}
if (line.hasOption("debug")) System.out.println("Sending: " + mh);
try {
double sleep = samplingRateValue * (1000000 / ((double) (dataRateValue * 1000 * 1000) / (double) ((octetsValue * packetsValue * 8))));
if (line.hasOption("debug")) System.out.println("Waiting: " + (long) sleep + " microseconds");
TimeUnit.MICROSECONDS.sleep((long) sleep);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (ParseException exp) {
System.err.println("Parsing failed. Reason: " + exp.getMessage() );
} catch (UtilityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (HeaderBytesException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}