/*******************************************************************************
* 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.layer2recodingScheme.encDNS_v0_001;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import org.apache.commons.lang3.ArrayUtils;
/**
* This class provides methods which are used by other EncDNS classes.
*
* @author Jens Lindemann
*/
public abstract class EncDNSHelper {
/**
* This method finds the end of the question name in a standard DNS message
* and returns its position.
* @param dnsmsg message to analyse
* @return position of the question name's end
*/
public static int findQuestionNameEnd(byte[] dnsmsg) {
int qNameEnd = 12; // question name starts at byte 12 of a DNS message
// read the length of a label and jump to the next length byte until
// we hit the terminating 0-length label
while(dnsmsg[qNameEnd] > 0) {
qNameEnd += dnsmsg[qNameEnd] + 1;
}
return qNameEnd;
}
/**
* Generates a standard DNS response signaling a server failure (SERVFAIL).
* @param query query for which a SERVFAIL response should be generated
* @return SERVFAIL response corresponding to query
*/
public static byte[] generateServfail(byte[] query) {
ByteBuffer buf = ByteBuffer.allocate(12);
// --- DNS HEADER ---
byte[] id = Arrays.copyOfRange(query, 0, 2);
buf.put(id);
buf.put((byte) 0x81); // QR=1 (response), OpCode=0000 (std. query), AA=0, TC=0, RD=1
buf.put((byte) 0x82); // RA=1, Z,AD,CD=0, RCode=2 (SERVFAIL)
buf.putShort((short) 0); // question count = 0
buf.putShort((short) 0); // answer count = 0
buf.putShort((short) 0); // authority count = 0
buf.putShort((short) 0); // additional count = 0
// convert to byte[]
byte[] out = new byte[buf.position()];
buf.position(0);
buf.get(out);
return out;
}
/**
* Converts a zone name passed as a String into a form which can be used in DNS
* messages (i.e. convert it to a byte[] and replace dots by label lengths).
* @param znstr zone name String to convert
* @return DNS representation of zone name
*/
public static byte[] parseZoneNameString(String znstr) {
ArrayList<Byte> al = new ArrayList<Byte>();
byte llen = 0;
// As we have to prepend the length to each label, it is easier to
// start at the end of the String.
for(int i = znstr.length()-1; i >= 0; i--) {
char c = znstr.charAt(i);
if(c == '.') {
al.add(0, llen);
llen = 0;
} else {
// A zone name is terminated by a 0-length label representing
// the root zone. Even if there is no . at the end of the
// String representation (which is quite common), we'll have
// to add this label.
if (i == (znstr.length()-1)) {
al.add((byte)0);
}
al.add(0, (byte)c);
llen++;
}
}
// There is no . at the beginning of a zone name, but we still have to
// add the first label length.
al.add(0, llen);
byte[] urlarray = ArrayUtils.toPrimitive(al.toArray(new Byte[0]));
return urlarray;
}
/**
* Reads a file and puts its contents in a byte[].
* WARNING: This will only read files of length<=Integer.MAX_VALUE
* and return null for longer files.
* @param filePath path of file to read
* @return byte[] containing file contents
*/
public static byte[] readByteArrayFromFile(String filePath) {
try {
File f = new File(filePath);
if(f.length()>=Integer.MAX_VALUE) {
System.err.println("Could not read file " + filePath + ": too large.");
return null; // We don't really need to read larger files and a byte[] can't be longer anyway...
}
int flen = (int)f.length();
byte[] array = new byte[flen];
DataInputStream is = new DataInputStream(new FileInputStream(filePath));
is.readFully(array);
return array;
} catch(FileNotFoundException e) {
System.err.println("File could not be found: " + filePath);
return null;
} catch(IOException e) {
System.err.println("Error when writing to file " + filePath);
return null;
}
}
/**
* Checks whether the operating system is Windows.
* @return true if running on Windows, false otherwise.
*/
public static boolean osIsWindows() {
String osname = System.getProperty("os.name", "generic").toLowerCase();
return osname.startsWith("windows");
}
/**
* Checks whether the operating system is Linux.
* @return true if running on Linux, false otherwise.
*/
public static boolean osIsLinux() {
String osname = System.getProperty("os.name", "generic").toLowerCase();
return osname.startsWith("linux");
}
/**
* Checks whether the operating system is Mac OS.
* @return true if running on Mac OS, false otherwise.
*/
public static boolean osIsMacOS() {
String osname = System.getProperty("os.name", "generic").toLowerCase();
return osname.startsWith("mac");
}
}