You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
357 lines
14 KiB
357 lines
14 KiB
// serverDNSCache.java
|
|
// -----------------------------
|
|
// (C) 2007 by Michael Peter Christen; mc@yacy.net, Frankfurt a. M., Germany
|
|
// first published 23.07.2007 on http://yacy.net
|
|
//
|
|
// $LastChangedDate: 2006-04-02 22:40:07 +0200 (So, 02 Apr 2006) $
|
|
// $LastChangedRevision: 1986 $
|
|
// $LastChangedBy: orbiter $
|
|
//
|
|
// LICENSE
|
|
//
|
|
// 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 2 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, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
package de.anomic.server;
|
|
|
|
import java.net.InetAddress;
|
|
import java.net.UnknownHostException;
|
|
import java.util.Collections;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
import de.anomic.kelondro.kelondroMScoreCluster;
|
|
import de.anomic.plasma.plasmaSwitchboard;
|
|
|
|
public class serverDomains {
|
|
|
|
// a dns cache
|
|
private static final Map nameCacheHit = Collections.synchronizedMap(new HashMap()); // a not-synchronized map resulted in deadlocks
|
|
private static final Set nameCacheMiss = Collections.synchronizedSet(new HashSet());
|
|
private static final kelondroMScoreCluster nameCacheHitAges = new kelondroMScoreCluster();
|
|
private static final kelondroMScoreCluster nameCacheMissAges = new kelondroMScoreCluster();
|
|
private static final int maxNameCacheHitAge = 24 * 60 * 60; // 24 hours in minutes
|
|
private static final int maxNameCacheMissAge = 24 * 60 * 60; // 24 hours in minutes
|
|
private static final int maxNameCacheHitSize = 3000;
|
|
private static final int maxNameCacheMissSize = 3000;
|
|
public static final List nameCacheNoCachingPatterns = Collections.synchronizedList(new LinkedList());
|
|
private static final Set nameCacheNoCachingList = Collections.synchronizedSet(new HashSet());
|
|
private static final long startTime = System.currentTimeMillis();
|
|
|
|
/**
|
|
* Converts the time to a non negative int
|
|
*
|
|
* @param longTime Time in miliseconds since 01/01/1970 00:00 GMT
|
|
* @return int seconds since startTime
|
|
*/
|
|
private static int intTime(long longTime) {
|
|
return (int) Math.max(0, ((longTime - startTime) / 1000));
|
|
}
|
|
|
|
/**
|
|
* Does an DNS-Check to resolve a hostname to an IP.
|
|
*
|
|
* @param host Hostname of the host in demand.
|
|
* @return String with the ip. null, if the host could not be resolved.
|
|
*/
|
|
public static InetAddress dnsResolveFromCache(String host) throws UnknownHostException {
|
|
if ((host == null) || (host.length() == 0)) return null;
|
|
host = host.toLowerCase().trim();
|
|
|
|
// trying to resolve host by doing a name cache lookup
|
|
InetAddress ip = (InetAddress) nameCacheHit.get(host);
|
|
if (ip != null) return ip;
|
|
|
|
if (nameCacheMiss.contains(host)) return null;
|
|
throw new UnknownHostException("host not in cache");
|
|
}
|
|
|
|
public static InetAddress dnsResolve(String host) {
|
|
if ((host == null) || (host.length() == 0)) return null;
|
|
host = host.toLowerCase().trim();
|
|
|
|
// trying to resolve host by doing a name cache lookup
|
|
InetAddress ip = (InetAddress) nameCacheHit.get(host);
|
|
if (ip != null) return ip;
|
|
|
|
if (nameCacheMiss.contains(host)) return null;
|
|
//System.out.println("***DEBUG dnsResolve(" + host + ")");
|
|
try {
|
|
boolean doCaching = true;
|
|
ip = InetAddress.getByName(host);
|
|
if ((ip == null) ||
|
|
(ip.isLoopbackAddress()) ||
|
|
(nameCacheNoCachingList.contains(ip.getHostName()))
|
|
) {
|
|
doCaching = false;
|
|
} else {
|
|
Iterator noCachingPatternIter = nameCacheNoCachingPatterns.iterator();
|
|
while (noCachingPatternIter.hasNext()) {
|
|
String nextPattern = (String) noCachingPatternIter.next();
|
|
if (ip.getHostName().matches(nextPattern)) {
|
|
// disallow dns caching for this host
|
|
nameCacheNoCachingList.add(ip.getHostName());
|
|
doCaching = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (doCaching) {
|
|
// remove old entries
|
|
flushHitNameCache();
|
|
|
|
// add new entries
|
|
synchronized (nameCacheHit) {
|
|
nameCacheHit.put(ip.getHostName(), ip);
|
|
nameCacheHitAges.setScore(ip.getHostName(), intTime(System.currentTimeMillis()));
|
|
}
|
|
}
|
|
return ip;
|
|
} catch (UnknownHostException e) {
|
|
// remove old entries
|
|
flushMissNameCache();
|
|
|
|
// add new entries
|
|
nameCacheMiss.add(host);
|
|
nameCacheMissAges.setScore(host, intTime(System.currentTimeMillis()));
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// /**
|
|
// * Checks wether an hostname already is in the DNS-cache.
|
|
// * FIXME: This method should use dnsResolve, as the code is 90% identical?
|
|
// *
|
|
// * @param host Searched for hostname.
|
|
// * @return true, if the hostname already is in the cache.
|
|
// */
|
|
// public static boolean dnsFetch(String host) {
|
|
// if ((nameCacheHit.get(host) != null) /*|| (nameCacheMiss.contains(host)) */) return false;
|
|
// try {
|
|
// String ip = InetAddress.getByName(host).getHostAddress();
|
|
// if ((ip != null) && (!(ip.equals("127.0.0.1"))) && (!(ip.equals("localhost")))) {
|
|
// nameCacheHit.put(host, ip);
|
|
// return true;
|
|
// }
|
|
// return false;
|
|
// } catch (UnknownHostException e) {
|
|
// //nameCacheMiss.add(host);
|
|
// return false;
|
|
// }
|
|
// }
|
|
|
|
/**
|
|
* Returns the number of entries in the nameCacheHit map
|
|
*
|
|
* @return int The number of entries in the nameCacheHit map
|
|
*/
|
|
public static int nameCacheHitSize() {
|
|
return nameCacheHit.size();
|
|
}
|
|
|
|
public static int nameCacheMissSize() {
|
|
return nameCacheMiss.size();
|
|
}
|
|
|
|
/**
|
|
* Returns the number of entries in the nameCacheNoCachingList list
|
|
*
|
|
* @return int The number of entries in the nameCacheNoCachingList list
|
|
*/
|
|
public static int nameCacheNoCachingListSize() {
|
|
return nameCacheNoCachingList.size();
|
|
}
|
|
|
|
|
|
/**
|
|
* Removes old entries from the dns hit cache
|
|
*/
|
|
public static void flushHitNameCache() {
|
|
int cutofftime = intTime(System.currentTimeMillis()) - maxNameCacheHitAge;
|
|
String k;
|
|
while ((nameCacheHitAges.size() > maxNameCacheHitSize) || (nameCacheHitAges.getMinScore() < cutofftime)) {
|
|
k = (String) nameCacheHitAges.getMinObject();
|
|
if (nameCacheHit.remove(k) == null) break; // ensure termination
|
|
nameCacheHitAges.deleteScore(k);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Removes old entries from the dns miss cache
|
|
*/
|
|
public static void flushMissNameCache() {
|
|
int cutofftime = intTime(System.currentTimeMillis()) - maxNameCacheMissAge;
|
|
String k;
|
|
while ((nameCacheMissAges.size() > maxNameCacheMissSize) || (nameCacheMissAges.getMinScore() < cutofftime)) {
|
|
k = (String) nameCacheMissAges.getMinObject();
|
|
if (!nameCacheMiss.remove(k)) break; // ensure termination
|
|
nameCacheMissAges.deleteScore(k);
|
|
}
|
|
|
|
}
|
|
|
|
private static InetAddress[] localAddresses = null;
|
|
static {
|
|
try {
|
|
localAddresses = InetAddress.getAllByName(InetAddress.getLocalHost().getHostName());
|
|
} catch (UnknownHostException e) {
|
|
localAddresses = new InetAddress[0];
|
|
}
|
|
}
|
|
|
|
public static boolean isLocal(String address) {
|
|
|
|
// attention! because this method does a dns resolve to look up an IP address,
|
|
// the result may be very slow. Consider 100 milliseconds per access
|
|
|
|
assert (address != null);
|
|
|
|
// check local ip addresses
|
|
if (address.equals("localhost") || address.startsWith("127")
|
|
|| address.startsWith("192.168")
|
|
|| address.startsWith("10.")
|
|
|| address.startsWith("169.254")
|
|
||
|
|
// 172.16.0.0-172.31.255.255 (I think this is faster than a regex)
|
|
(address.startsWith("172.") && (address.startsWith("172.16.")
|
|
|| address.startsWith("172.17.")
|
|
|| address.startsWith("172.18.")
|
|
|| address.startsWith("172.19.")
|
|
|| address.startsWith("172.20.")
|
|
|| address.startsWith("172.21.")
|
|
|| address.startsWith("172.22.")
|
|
|| address.startsWith("172.23.")
|
|
|| address.startsWith("172.24.")
|
|
|| address.startsWith("172.25.")
|
|
|| address.startsWith("172.26.")
|
|
|| address.startsWith("172.27.")
|
|
|| address.startsWith("172.28.")
|
|
|| address.startsWith("172.29.")
|
|
|| address.startsWith("172.30.")
|
|
|| address.startsWith("172.31."))))
|
|
return true;
|
|
|
|
// make a dns resolve if a hostname is given and check again
|
|
final InetAddress clientAddress = dnsResolve(address);
|
|
if (clientAddress != null) {
|
|
if ((clientAddress.isAnyLocalAddress()) || (clientAddress.isLoopbackAddress())) return true;
|
|
if (address.charAt(0) > '9') address = clientAddress.getHostAddress();
|
|
}
|
|
|
|
// finally check if there are other local IP adresses that are not in
|
|
// the standard IP range
|
|
for (int i = 0; i < localAddresses.length; i++) {
|
|
if (localAddresses[i].equals(clientAddress)) return true;
|
|
}
|
|
|
|
// the address must be a global address
|
|
return false;
|
|
}
|
|
|
|
public static String myPublicIP() {
|
|
try {
|
|
|
|
// if a static IP was configured, we have to return it here ...
|
|
plasmaSwitchboard sb = plasmaSwitchboard.getSwitchboard();
|
|
if (sb != null) {
|
|
String staticIP = sb.getConfig("staticIP", "");
|
|
if ((!staticIP.equals(""))) {
|
|
return staticIP;
|
|
}
|
|
}
|
|
|
|
// If port forwarding was enabled we need to return the remote IP
|
|
// Address
|
|
if ((serverCore.portForwardingEnabled) && (serverCore.portForwarding != null)) {
|
|
// does not return serverCore.portForwarding.getHost(), because
|
|
// hostnames are not valid, except in DebugMode
|
|
return InetAddress.getByName(
|
|
serverCore.portForwarding.getHost()).getHostAddress();
|
|
}
|
|
|
|
// otherwise we return the real IP address of this host
|
|
InetAddress pLIP = myPublicLocalIP();
|
|
if (pLIP != null) return pLIP.getHostAddress();
|
|
return null;
|
|
} catch (java.net.UnknownHostException e) {
|
|
System.err.println("ERROR: (internal) " + e.getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static InetAddress myPublicLocalIP() {
|
|
try {
|
|
String hostName;
|
|
try {
|
|
hostName = InetAddress.getLocalHost().getHostName();
|
|
} catch (java.net.UnknownHostException e) {
|
|
hostName = "localhost"; // hopin' nothing serious happened only the hostname changed while running yacy
|
|
System.err.println("ERROR: (internal) " + e.getMessage());
|
|
}
|
|
// list all addresses
|
|
InetAddress[] ia = InetAddress.getAllByName(hostName);
|
|
// for (int i = 0; i < ia.length; i++) System.out.println("IP: " +
|
|
// ia[i].getHostAddress()); // DEBUG
|
|
if (ia.length == 0) {
|
|
try {
|
|
return InetAddress.getLocalHost();
|
|
} catch (UnknownHostException e) {
|
|
try {
|
|
return InetAddress.getByName("127.0.0.1");
|
|
} catch (UnknownHostException ee) {
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
if (ia.length == 1) {
|
|
// only one network connection available
|
|
return ia[0];
|
|
}
|
|
// we have more addresses, find an address that is not local
|
|
int b0, b1;
|
|
for (int i = 0; i < ia.length; i++) {
|
|
b0 = 0Xff & ia[i].getAddress()[0];
|
|
b1 = 0Xff & ia[i].getAddress()[1];
|
|
if ((b0 != 10) && // class A reserved
|
|
(b0 != 127) && // loopback
|
|
((b0 != 172) || (b1 < 16) || (b1 > 31)) && // class B reserved
|
|
((b0 != 192) || (b1 != 168)) && // class C reserved
|
|
(ia[i].getHostAddress().indexOf(":") < 0))
|
|
return ia[i];
|
|
}
|
|
// there is only a local address, we filter out the possibly
|
|
// returned loopback address 127.0.0.1
|
|
for (int i = 0; i < ia.length; i++) {
|
|
if (((0Xff & ia[i].getAddress()[0]) != 127) && (ia[i].getHostAddress().indexOf(":") < 0)) return ia[i];
|
|
}
|
|
// if all fails, give back whatever we have
|
|
for (int i = 0; i < ia.length; i++) {
|
|
if (ia[i].getHostAddress().indexOf(":") < 0) return ia[i];
|
|
}
|
|
return ia[0];
|
|
} catch (java.net.UnknownHostException e) {
|
|
System.err.println("ERROR: (internal) " + e.getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
}
|