/*******************************************************************************
* 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.encDNS_v0_001;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.util.Random;
import org.xbill.DNS.Cache;
import org.xbill.DNS.Credibility;
import org.xbill.DNS.DClass;
import org.xbill.DNS.ExtendedResolver;
import org.xbill.DNS.Flags;
import org.xbill.DNS.Message;
import org.xbill.DNS.Record;
import org.xbill.DNS.Section;
import org.xbill.DNS.SetResponse;
import staticContent.framework.EncDnsServer;
import staticContent.framework.config.Settings;
import userGeneratedContent.testbedPlugIns.layerPlugIns.layer5application.dnsProxy_v0_001.DNSUtils;
public class LocalResolver {
private static String[] dnsServers;
/** Flag indicating if all DNS queries shall get an A record of 127.0.0.1 instead of
* really resolving them through the DNS server */
private final boolean RESOLVE_ALL_DNS_TO_LOCALHOST;
/** The resolver object to use for resolving the DNS queries */
private static ExtendedResolver res;
/** Random number generator for performing the DNS lookups with a random DNS server */
private static final Random r = new SecureRandom();
/** Local DNS cache that answers queries if the records are cached */
private Cache dnsCache = new Cache(DClass.IN);
//private final int RESOLVER_TIMEOUT;
private boolean SIMULATE_RESOLVE_PROCESS;
public LocalResolver(boolean resolveLocal/*, int timeout*/, Settings settings) {
this.RESOLVE_ALL_DNS_TO_LOCALHOST = resolveLocal;
this.SIMULATE_RESOLVE_PROCESS = settings.getPropertyAsBoolean("SIMULATE_RESOLVE_PROCESS");
String dnsServerString = settings.getProperty("DNS_SERVERS");
dnsServerString = dnsServerString.replaceAll(" ", "");
LocalResolver.dnsServers = dnsServerString.split(",");
//this.RESOLVER_TIMEOUT = timeout;
/*this.DNSP_DEBUG = settings.getPropertyAsBoolean("DNSP_DEBUG");
this.RESOLVE_ALL_DNS_TO_LOCALHOST = settings.getPropertyAsBoolean("RESOLVE_ALL_DNS_TO_LOCALHOST");
this.RESOLVER_TIMEOUT = settings.getPropertyAsInt("RESOLVER_TIMEOUT");*/
try {
res = new ExtendedResolver(dnsServers);
res.setLoadBalance(true);
//res.setTimeout(RESOLVER_TIMEOUT);
res.setRetries(0);
} catch (UnknownHostException e) {
e.printStackTrace();
throw new RuntimeException("could not set up resolver");
}
}
public byte[] resolve(byte[] request) throws IOException {
if (SIMULATE_RESOLVE_PROCESS) {
// Open a socket on a new port
DatagramSocket udpSock = null;
int port;
while (udpSock == null) {
try {
port = 1024 + EncDnsServer.rnd.nextInt(64512);
udpSock = new DatagramSocket(port);
} catch (SocketException e) {
// do nothing as this is being handled by the while loop
}
}
// Send the decrypted query to the remote recursive nameserver
DatagramPacket sendPacket = new DatagramPacket(request, request.length, udpSock.getLocalAddress(), udpSock.getLocalPort());
udpSock.send(sendPacket);
// Wait for a response
byte[] rcvbytes = new byte[EncDnsServer.MAX_MSG_SIZE];
DatagramPacket rcvPkt = new DatagramPacket(rcvbytes, rcvbytes.length);
udpSock.setSoTimeout(EncDnsServer.timeout); // Make sure we do not wait for ages...
udpSock.receive(rcvPkt);
udpSock.close();
byte[] rcvDNS = new byte[rcvPkt.getLength()];
System.arraycopy(rcvPkt.getData(), rcvPkt.getOffset(), rcvDNS, 0, rcvPkt.getLength());
if(EncDnsServer.verbosity >= 1) {
System.out.println("Received reply from aNS");
}
return DNSUtils.resolveDNSQueryToLocalhost(new Message(request).toWire());
} else {
byte[] data;
Message dnsQuery = new Message(request);
SetResponse cached;
synchronized(dnsCache) {
cached = dnsCache.lookupRecords(dnsQuery.getQuestion().getName(), dnsQuery.getQuestion().getType(), Credibility.NONAUTH_ANSWER);
}
if (cached.isSuccessful() && !RESOLVE_ALL_DNS_TO_LOCALHOST) {
Record[] r = DNSUtils.processSetResponse(cached);
for (Record rec : r){
dnsQuery.addRecord(rec, Section.ANSWER);
}
dnsQuery.getHeader().setFlag(Flags.RA);
dnsQuery.getHeader().setFlag(Flags.QR);
data = dnsQuery.toWire();
} else if(RESOLVE_ALL_DNS_TO_LOCALHOST){
data = DNSUtils.resolveDNSQueryToLocalhost(dnsQuery.toWire());
} else {
Message dnsReply = res.getResolver(r.nextInt(dnsServers.length)).send(dnsQuery);
data = dnsReply.toWire();
}
return data;
}
}
}