/*
* Copyright 2016 christopher.metter.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.uniwuerzburg.info3.ofcprobe.vswitch.trafficgen;
import org.openflow.util.HexString;
import de.uniwuerzburg.info3.ofcprobe.util.AddressPositions;
import de.uniwuerzburg.info3.ofcprobe.util.Util;
import de.uniwuerzburg.info3.ofcprobe.vswitch.main.config.Config;
import de.uniwuerzburg.info3.ofcprobe.vswitch.trafficgen.ipgen.IIpGenerator;
import de.uniwuerzburg.info3.ofcprobe.vswitch.trafficgen.ipgen.RandomIPv4Generator;
import de.uniwuerzburg.info3.ofcprobe.vswitch.trafficgen.ipgen.SerialIPGenerator;
import de.uniwuerzburg.info3.ofcprobe.vswitch.trafficgen.macgen.IMacGen;
import de.uniwuerzburg.info3.ofcprobe.vswitch.trafficgen.macgen.RandomMacGen;
import de.uniwuerzburg.info3.ofcprobe.vswitch.trafficgen.macgen.SerialMacGen;
import de.uniwuerzburg.info3.ofcprobe.vswitch.trafficgen.portgen.IPortGen;
import de.uniwuerzburg.info3.ofcprobe.vswitch.trafficgen.portgen.RandomPortGen;
import de.uniwuerzburg.info3.ofcprobe.vswitch.trafficgen.portgen.SerialPortGen;
import java.util.concurrent.atomic.AtomicInteger;
/**
* This Class generates Payload. atm only random TCP Syns supported
*
* @author Christopher Metter(christopher.metter@informatik.uni-wuerzburg.de)
*
*/
public class PayLoadGen {
AtomicInteger nextIpId;
/**
* Connected IPGenerator
*/
private IIpGenerator ipGen;
/**
* Connected MACGenerator
*/
private IMacGen macGen;
/**
* Connected PortGenerator
*/
private IPortGen portGen;
/**
* Here to save the world.
*/
private final byte[] tcpSynMaster;
/**
* Constructor, initializes the Generators
*/
public PayLoadGen(Config config) {
this.nextIpId = new AtomicInteger();
switch (config.getTrafficGenConfig().getMacGenType()) {
case RANDOM:
this.macGen = new RandomMacGen();
break;
case SERIAL:
this.macGen = new SerialMacGen();
break;
default:
this.macGen = new SerialMacGen();
break;
}
switch (config.getTrafficGenConfig().getIPGenType()) {
case RANDOM:
this.ipGen = new RandomIPv4Generator();
break;
case SERIAL:
this.ipGen = new SerialIPGenerator();
break;
default:
this.ipGen = new SerialIPGenerator();
break;
}
switch (config.getTrafficGenConfig().getPortGenType()) {
case RANDOM:
this.portGen = new RandomPortGen();
break;
case SERIAL:
this.portGen = new SerialPortGen();
break;
default:
this.portGen = new SerialPortGen();
break;
}
this.tcpSynMaster = preGenerateTcpSyn();
}
/**
* Pregenerates a TCPSYN Packet. So all Fields of the Packet that are always
* the same are set.
*
* @return a pregenarted TCPSyn
*/
private byte[] preGenerateTcpSyn() {
byte[] packet = new byte[66];
// Inserting MAC Header Fields
byte[] macType = Util.toByteArray("0800"); // Type = IP
packet = Util.insertByteArray(packet, macType, AddressPositions.ETHER_TYPE);
// Inserting IP Header Fields
byte[] ipverServiceLengthIdentiFlagsTTLProtocol = Util.toByteArray("450000345ad340008006"); // IP Version + Services + TotalIPHeaderLength + Identification + IPFlags + TTL + Protocol(TCP)
//5ad3 = IP ID
packet = Util.insertByteArray(packet, ipverServiceLengthIdentiFlagsTTLProtocol, 14);
// Inserting TCP Header Fields
byte[] seqNrFlagsWindowsize = Util.toByteArray("6a9ef8220000000080023908"); // TCP Seq NR, Flags(SYN), WindowSize
byte[] options = Util.toByteArray("020405b40402080a091273c70000000001030307"); // TCP Options
packet = Util.insertByteArray(packet, seqNrFlagsWindowsize, 38);
packet = Util.insertByteArray(packet, options, 54);
return packet;
}
/**
* Generate new TCPSyn Packet
*
* @return a randomly genrated TCPSyn Packet
*/
public byte[] generateTCPSyn() {
byte[] packet = tcpSynMaster;
packet = buildMacHeader(packet, this.macGen.getMac(), this.macGen.getMac());
packet = buildIpHeader(packet, this.ipGen.getIp(), this.ipGen.getIp());
packet = buildTcpHeader(packet, this.portGen.getPort(), this.portGen.getPrivilegdedPort());
return packet;
}
/**
* Creates a Custom TCP Syn with provided addresses and random Ports
*
* @param macSrc the MacSrc
* @param macDst the MacDst
* @param ipSrc the IPSrc
* @param ipDst the IPDst
* @return the TCPSyn
*/
public byte[] generateCustomTCPSyn(byte[] macSrc, byte[] macDst, byte[] ipSrc, byte[] ipDst) {
byte[] packet = tcpSynMaster;
packet = buildMacHeader(packet, macSrc, macDst);
packet = buildIpHeader(packet, ipSrc, ipDst);
packet = buildTcpHeader(packet, this.portGen.getPort(), this.portGen.getPrivilegdedPort());
return packet;
}
/**
* Generate Custom TCP Syn with provided addresses (as String) and random
* Ports
*
* @param macSrc the MacSrc
* @param macDst the MacDst
* @param ipSrc the IPSrc
* @param ipDst the IPDst
* @return the TCPSyn
*/
public byte[] generateCustomTCPSynfromStrings(String macSrc, String macDst, String ipSrc, String ipDst) {
byte[] packet = tcpSynMaster;
packet = buildMacHeader(packet, HexString.fromHexString(macSrc), HexString.fromHexString(macDst));
packet = buildIpHeader(packet, Util.toIPv4AddressBytes(ipSrc), Util.toIPv4AddressBytes(ipDst));
packet = buildTcpHeader(packet, this.portGen.getPort(), this.portGen.getPrivilegdedPort());
return packet;
}
/**
* Builds the TCP Header with Random Ports.
*
* @param packet the packet in which the TCP Header will be inserted
* @return the inserted packet with TCP Header.
*/
private byte[] buildTcpHeader(byte[] packet, byte[] srcPort, byte[] dstPort) {
packet = Util.insertByteArray(packet, srcPort, AddressPositions.TCP_PORT_SRC);
packet = Util.insertByteArray(packet, dstPort, AddressPositions.TCP_PORT_DST);
long checksumL = checksum(packet, 32, 34);
Util.insertLong(packet, checksumL, 50, 2);
return packet;
}
/**
* Builds the IP Header with Random IPs.
*
* @param packet the packet in which the IP Header will be inserted
* @return the inserted packet with IP Header.
*/
private byte[] buildIpHeader(byte[] packet, byte[] ipSrc, byte[] ipDst) {
packet = Util.insertByteArray(packet, ipSrc, 26);
packet = Util.insertByteArray(packet, ipDst, 30);
packet = insertIpId(packet, this.nextIpId.getAndIncrement());
long checksum = checksum(packet, 20, 14);
Util.insertLong(packet, checksum, 24, 2);
return packet;
}
public byte[] insertIpId(byte[] packet, int ipId) {
if (ipId > 65535) {
this.nextIpId = new AtomicInteger();
ipId = this.nextIpId.getAndIncrement();
}
String hexString = Integer.toHexString(ipId);
if ((hexString.length() % 2) != 0) {
hexString = "0" + hexString;
}
byte[] ipIdbyte = hexStringToByteArray(hexString);
packet = Util.insertByteArray(packet, ipIdbyte, 18);
return packet;
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}
/**
* Builds the MAC Header with MAC Addresses.
*
* @param packet the packet in which the MAC Header will be inserted
* @return the inserted packet with MAC Header.
*/
private byte[] buildMacHeader(byte[] packet, byte[] macSrc, byte[] macDst) {
packet = Util.insertByteArray(packet, macDst, AddressPositions.ETHER_MAC_DST);
packet = Util.insertByteArray(packet, macSrc, AddressPositions.ETHER_MAC_SRC);
return packet;
}
/**
* Calculates a checksum for IP or TCP Header
*
* @param buf the packet with the header
* @param length length of the header
* @param offset startingposition of the header
* @return checksum of the header
*/
private long checksum(byte[] buf, int length, int offset) {
int i = 0;
long sum = 0;
while (length > 0) {
sum += (buf[offset + i++] & 0xff) << 8;
if ((--length) == 0) {
break;
}
sum += (buf[offset + i++] & 0xff);
--length;
}
return (~((sum & 0xFFFF) + (sum >> 16))) & 0xFFFF;
}
}