/*******************************************************************************
* gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/
* Copyright (C) 2014 SVS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
package userGeneratedContent.testbedPlugIns.layerPlugIns.layer5application.dnsProxy_v0_001;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;
import org.xbill.DNS.AAAARecord;
import org.xbill.DNS.ARecord;
import org.xbill.DNS.DClass;
import org.xbill.DNS.Flags;
import org.xbill.DNS.Header;
import org.xbill.DNS.Message;
import org.xbill.DNS.PTRRecord;
import org.xbill.DNS.RRset;
import org.xbill.DNS.Rcode;
import org.xbill.DNS.Record;
import org.xbill.DNS.SRVRecord;
import org.xbill.DNS.Section;
import org.xbill.DNS.SetResponse;
import org.xbill.DNS.Type;
public class DNSUtils {
private static long longToByteArrayCounter = 0l;
private static long byteArrayToLongCounter = 0l;
private static long intToByteArrayCounter = 0l;
private static long byteArrayToIntCounter = 0l;
private static long shortToByteArrayCounter = 0l;
private static long byteArrayToShortCounter = 0l;
private static long mergeArraysCounter = 0l;
private static long byteListToPrimitiveArrayListCounter = 0l;
private static long getHexCounter = 0l;
private static long splitArrayOnPatternCounter = 0l;
private static long indexOfCounter = 0l;
private static long processSetResponseCounter = 0l;
private static long resolveDNSToLocalhostCounter = 0l;
private static long formerrMessageForDNSQueryCounter = 0l;
private static final InetAddress LOCALHOST;
private static final InetAddress LOCALHOST_V6;
public static final byte[] dnsTerminator = new byte[]{(byte)0xfa,(byte)0xfb,(byte)0xfc,(byte)0xfd,(byte)0xfe};
/**
* Empty constructor. Never used since all methods are static.
*/
private DNSUtils() {
}
static {
InetAddress temp = null;
InetAddress temp2 = null;
try {
temp = InetAddress.getLocalHost();
temp2 = InetAddress.getByName("::1");
} catch (UnknownHostException e) {
e.printStackTrace();
}
LOCALHOST = temp;
LOCALHOST_V6 = temp2;
}
private static ByteBuffer tempBuffer = ByteBuffer.allocate(2048);
private static final DateFormat dateFormat= new SimpleDateFormat("yyyy-dd-MM_HH-mm-ss");
/**
* Converts the bypassed long value to a byte array.
*
* @param source The long value to be translated.
* @return Byte array representation of the bypassed long value.
*/
public static byte[] longToByteArray(long source) {
long methodStart = System.nanoTime();
byte[] result = new byte[8];
for (int i=0; i<8; i++) {
result[i] = new Long((source >> (i << 3)) & 255L).byteValue();
}
long methodEnd = System.nanoTime();
longToByteArrayCounter+= methodEnd-methodStart;
return result;
}
/**
* Converts the bypassed byte array to a long value.
*
* @param byteArray The byte array to be translated.
* @return "long" representation of the bypassed byte array.
*/
public static long byteArrayToLong(byte[] byteArray) {
long methodStart = System.nanoTime();
long result = 0;
for (int i=0; (i<byteArray.length) && (i<8); i++) {
result |= ((((long) byteArray[i]) & 255L) << (i << 3));
}
long methodEnd = System.nanoTime();
byteArrayToLongCounter+= methodEnd-methodStart;
return result;
}
/**
* Converts the bypassed int value to a byte array.
*
* @param source The int value to be translated.
* @return Byte array representation of the bypassed int value.
*/
public static byte[] intToByteArray(int source) {
long methodStart = System.nanoTime();
byte[] result = new byte[4];
for (int i = 0; i < 4; ++i) {
result[3-i] = (byte)((source & (0xff << (i << 3))) >>> (i << 3));
}
long methodEnd = System.nanoTime();
intToByteArrayCounter+= methodEnd-methodStart;
return result;
}
/**
* Converts the bypassed byte array to an int value.
*
* @param byteArray The byte array to be translated.
* @return "int" representation of the bypassed byte array.
*/
public static int byteArrayToInt(byte[] byteArray) {
long methodStart = System.nanoTime();
int result = 0;
for (int i = 0; (i<byteArray.length) && (i<8); i++) {
result |= (byteArray[3-i] & 0xff) << (i << 3);
}
long methodEnd = System.nanoTime();
byteArrayToIntCounter+= methodEnd-methodStart;
return result;
}
/**
* Converts the bypassed short value to a byte array.
*
* @param source The short value to be translated.
* @return Byte array representation of the bypassed short value.
*/
public static byte[] shortToByteArray(int source) {
long methodStart = System.nanoTime();
byte[] result = new byte[2];
result[0] = (byte)((source & 0xFF00) >> 8);
result[1] = (byte)(source & 0x00FF);
long methodEnd = System.nanoTime();
shortToByteArrayCounter+= methodEnd-methodStart;
return result;
}
/**
* Converts the bypassed byte array to a short value.
*
* @param byteArray The byte array to be translated.
* @return "short" representation of the bypassed byte array.
*/
public static int byteArrayToShort(byte[] byteArray) {
long methodStart = System.nanoTime();
int result = 0;
result |= (byteArray[0] & 0xFF);
result <<= 8;
result |= (byteArray[1] & 0xFF);
long methodEnd = System.nanoTime();
byteArrayToShortCounter+= methodEnd-methodStart;
return result;
}
/**
* Merges the bypassed byte arrays (<code>secondArray</code> is appended to
* <code>firstArray</code>).
*
* @param firstArray Array to be extended.
* @param bytes Array to be appended.
*
* @return Merged array.
*/
public static byte[] mergeArrays(byte[] firstArray, byte[] bytes) {
long methodStart = System.nanoTime();
byte[] result = new byte[firstArray.length + bytes.length];
System.arraycopy(firstArray, 0, result, 0, firstArray.length);
System.arraycopy( bytes,
0, result,
firstArray.length,
bytes.length
);
long methodEnd = System.nanoTime();
mergeArraysCounter+= methodEnd-methodStart;
return result;
}
public static byte[] byteListToPrimitiveArray(List<byte[]> list) {
long methodStart = System.nanoTime();
Iterator<byte[]> it = list.iterator();
byte[] ret;
synchronized(tempBuffer){
while (it.hasNext()){
tempBuffer.put(it.next());
}
ret = new byte[tempBuffer.position()];
tempBuffer.flip();
tempBuffer.get(ret).clear();
}
long methodEnd = System.nanoTime();
byteListToPrimitiveArrayListCounter+= methodEnd-methodStart;
return ret;
}
/** http://rgagnon.com/javadetails/java-0596.html*/
static final String HEXES = "0123456789ABCDEF";
public static String getHex( byte [] raw ) {// TODO change code, very slow!
if ( raw == null ) {
return null;
}
final StringBuilder hex = new StringBuilder( 2 * raw.length );
for ( final byte b : raw ) {
hex.append(HEXES.charAt((b & 0xF0) >> 4))
.append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
/** http://helpdesk.objects.com.au/java/search-a-byte-array-for-a-byte-sequence bzw
* http://stackoverflow.com/questions/1507780/searching-for-a-sequence-of-bytes-in-a-binary-file-with-java
*/
/**
* Finds the first occurrence of the pattern in the text.
*/
/*public static int indexOf(byte[] data, byte[] pattern) {
int[] failure = computeFailure(pattern);
System.out.println("failure is " + Arrays.toString(failure));
int j = failure[failure.length-1];
if (data.length == 0) return -1;
for (int i = 0; i < data.length; i++) {
while (j > 0 && pattern[j] != data[i]) {
System.out.println("fail");
j = failure[j - 1];
}
if (pattern[j] == data[i]) { j++; }
if (j == pattern.length) {
System.out.println("found");
return i - pattern.length + 1;
}
}
return -1;
}*/
/*
* Computes the failure function using a boot-strapping process,
* where the pattern is matched against itself.
private static int[] computeFailure(byte[] pattern) {
int[] failure = new int[pattern.length];
int j = 0;
for (int i = 1; i < pattern.length; i++) {
while (j > 0 && pattern[j] != pattern[i]) {
j = failure[j - 1];
}
if (pattern[j] == pattern[i]) {
j++;
}
failure[i] = j;
}
return failure;
} */
public static List<byte[]> splitArrayOnPattern(byte[] data, byte[] pattern, int start){//dnsclient needs start 4 (skip msg length), proxy connection handler needs 0
long methodStart = System.nanoTime();
List<byte[]> arrayList = new ArrayList<byte[]>();
// check if inside
int index = IndexOf(data, pattern);
if (index == -1){
byte[] msg = Arrays.copyOfRange(data, start, data.length);
arrayList.add(msg);
return arrayList;
}
while ( -1 != (index = IndexOf(data, pattern)) ){
byte[] msg = Arrays.copyOfRange(data, start, index);
if (msg.length > 0){
arrayList.add(msg);
}
//System.out.println("msg added: " + getHex(msg));
data = Arrays.copyOfRange(data, index+5, data.length);
//System.out.println("data for next round: " + getHex(data));
start = 0;
}
long methodEnd = System.nanoTime();
splitArrayOnPatternCounter+= methodEnd-methodStart;
return arrayList;
}
// TODO rework this, copy of http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/15514c1a-b6a1-44f5-a06c-9b029c4164d7
// Problem: if pattern matches no subsequent match is checked
public static int IndexOf(byte[] arrayToSearchThrough, byte[] patternToFind)
{
long methodStart = System.nanoTime();
if (patternToFind.length > arrayToSearchThrough.length)
return -1;
for (int i = 0; i < arrayToSearchThrough.length; i++)
{
boolean found = true;
int index = 0;
for (int j = 0; j < patternToFind.length; j++)
{
index = i+j > arrayToSearchThrough.length-1 ? i : i+j;
if (arrayToSearchThrough[index] != patternToFind[j])
{
found = false;
break;
}
}
if (found)
{
long methodEnd = System.nanoTime();
indexOfCounter+= methodEnd-methodStart;
return i;
}
}
long methodEnd = System.nanoTime();
indexOfCounter+= methodEnd-methodStart;
return -1;
}
/** Taken from package org.apache.james.dnsserver; */
public static Record[] processSetResponse(SetResponse sr) {
long methodStart = System.nanoTime();
Record [] answers;
int answerCount = 0, n = 0;
RRset [] rrsets = sr.answers();
answerCount = 0;
for (int i = 0; i < rrsets.length; i++) {
answerCount += rrsets[i].size();
}
answers = new Record[answerCount];
for (int i = 0; i < rrsets.length; i++) {
@SuppressWarnings("rawtypes")
Iterator iter = rrsets[i].rrs();
while (iter.hasNext()) {
Record r = (Record)iter.next();
answers[n++] = r;
}
}
long methodEnd = System.nanoTime();
processSetResponseCounter+= methodEnd-methodStart;
return answers;
}
/**
* TODO
* @param dnsQueryInWire
* @return
*/
public static byte[] resolveDNSQueryToLocalhost(byte[] dnsQueryInWire){
// TODO make it faster?
long methodStart = System.nanoTime();
Message msg = null;
try {
msg = new Message(dnsQueryInWire);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
return new byte[0];
}
int queryType = msg.getQuestion().getType();
switch (queryType){
case Type.PTR:
msg.addRecord(new PTRRecord(msg.getQuestion().getName(), DClass.IN, 1, msg.getQuestion().getName()), Section.ANSWER);
case Type.AAAA:
msg.addRecord(new AAAARecord(msg.getQuestion().getName(), DClass.IN, 1, LOCALHOST_V6), Section.ANSWER);
case Type.SRV:
msg.addRecord(new SRVRecord(msg.getQuestion().getName(), DClass.IN, 1, 0, 5, 12345, msg.getQuestion().getName()), Section.ANSWER);
case Type.A:
default:
msg.addRecord(new ARecord(msg.getQuestion().getName(), DClass.IN, 1, LOCALHOST), Section.ANSWER);
}
msg.getHeader().setFlag(Flags.RA);
msg.getHeader().setFlag(Flags.QR);
long methodEnd = System.nanoTime();
resolveDNSToLocalhostCounter+= methodEnd-methodStart;
return msg.toWire();
}
//copyed from jnamed bwelling@xbill.org
public static byte[] formerrMessageForDNSQuery(byte[] in) {
long methodStart = System.nanoTime();
Header header;
try {
header = new Header(in);
} catch (IOException e) {
return new byte[0];
}
Message response = new Message();
response.setHeader(header);
for (int i = 0; i < 4; i++) {
response.removeAllRecords(i);
}
header.setRcode(Rcode.FORMERR);
long methodEnd = System.nanoTime();
formerrMessageForDNSQueryCounter+= methodEnd-methodStart;
return response.toWire();
}
public static String getCurrentDateTimeForFilename(){
return dateFormat.format(Calendar.getInstance().getTime());
}
public static void printValues(){
StringBuffer sb = new StringBuffer();
sb.append("longToByteArrayCounter: " + TimeUnit.NANOSECONDS.toMillis(longToByteArrayCounter)).append(System.getProperty("line.separator"));
sb.append("byteArrayToLongCounter: " + TimeUnit.NANOSECONDS.toMillis(byteArrayToLongCounter)).append(System.getProperty("line.separator"));
sb.append("intToByteArrayCounter: " + TimeUnit.NANOSECONDS.toMillis(intToByteArrayCounter)).append(System.getProperty("line.separator"));
sb.append("byteArrayToIntCounter: " + TimeUnit.NANOSECONDS.toMillis(byteArrayToIntCounter)).append(System.getProperty("line.separator"));
sb.append("shortToByteArrayCounter: " + TimeUnit.NANOSECONDS.toMillis(shortToByteArrayCounter)).append(System.getProperty("line.separator"));
sb.append("byteArrayToShortCounter: " + TimeUnit.NANOSECONDS.toMillis(byteArrayToShortCounter)).append(System.getProperty("line.separator"));
sb.append("mergeArraysCounter: " + TimeUnit.NANOSECONDS.toMillis(mergeArraysCounter)).append(System.getProperty("line.separator"));
sb.append("byteListToPrimitiveArrayListCounter: " + TimeUnit.NANOSECONDS.toMillis(byteListToPrimitiveArrayListCounter)).append(System.getProperty("line.separator"));
sb.append("getHexCounter: " + TimeUnit.NANOSECONDS.toMillis(getHexCounter)).append(System.getProperty("line.separator"));
sb.append("splitArrayOnPatternCounter: " + TimeUnit.NANOSECONDS.toMillis(splitArrayOnPatternCounter)).append(System.getProperty("line.separator"));
sb.append("indexOfCounter: " + TimeUnit.NANOSECONDS.toMillis(indexOfCounter)).append(System.getProperty("line.separator"));
sb.append("processSetResponseCounter: " + TimeUnit.NANOSECONDS.toMillis(processSetResponseCounter)).append(System.getProperty("line.separator"));
sb.append("resolveDNSToLocalhostCounter: " + TimeUnit.NANOSECONDS.toMillis(resolveDNSToLocalhostCounter)).append(System.getProperty("line.separator"));
sb.append("formerrMessageForDNSQueryCounter: " + TimeUnit.NANOSECONDS.toMillis(formerrMessageForDNSQueryCounter)).append(System.getProperty("line.separator"));
System.out.println(sb.toString());
}
}