package plugins.JSTUN; import java.lang.reflect.Method; import java.net.BindException; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.UnknownHostException; import java.util.Enumeration; import java.util.HashSet; import java.util.Vector; import java.util.Random; import org.tanukisoftware.wrapper.WrapperManager; import plugins.JSTUN.de.javawi.jstun.test.DiscoveryInfo; import plugins.JSTUN.de.javawi.jstun.test.DiscoveryTest_; import freenet.pluginmanager.DetectedIP; import freenet.pluginmanager.FredPlugin; import freenet.pluginmanager.FredPluginHTTP; import freenet.pluginmanager.FredPluginIPDetector; import freenet.pluginmanager.FredPluginThreadless; import freenet.pluginmanager.FredPluginVersioned; import freenet.pluginmanager.PluginHTTPException; import freenet.pluginmanager.PluginRespirator; import freenet.support.HTMLNode; import freenet.support.Logger; import freenet.support.api.HTTPRequest; // threadless in the sense that it doesn't need a thread running all the time. // but getAddress() can and will block! public class JSTUN implements FredPlugin, FredPluginIPDetector, FredPluginThreadless, FredPluginHTTP, FredPluginVersioned { // From http://www.voip-info.org/wiki-STUN String[] publicSTUNServers = new String[] { "stun.ekiga.net", "stun.fwdnet.net", "stun.ideasip.com", "stun01.sipphone.com", "stun.softjoys.com", "stun.voipbuster.org", "stun.voxgratia.org", "stun.xten.com" }; private DiscoveryInfo reportedData; private PluginRespirator pr; private boolean hasRunTestBeenCalled = false; DetectedIP[] runTest(InetAddress iaddress) { this.hasRunTestBeenCalled = true; Random r = new Random(); // FIXME use something safer? Vector v = new Vector(publicSTUNServers.length); Vector out = new Vector(); int countLikely = 0; int countUnlikely = 0; for(int i=0;i= 3 || countLikely >= 2 || v.isEmpty()) return (DetectedIP[])out.toArray(new DetectedIP[out.size()]); } catch (BindException be) { System.err.println(iaddress.toString() + ": " + be.getMessage()); } catch (UnknownHostException e) { System.err.println("Could not find the STUN server "+stunServer+" : "+e+" - DNS problems? Trying another..."); } catch (SocketException e) { System.err.println("Could not connect to the STUN server: "+stunServer+" : "+e+" - trying another..."); } catch (Exception e) { System.err.println("Failed to run STUN to server "+stunServer+": "+e+" - trying another, report if persistent"); e.printStackTrace(); } } System.err.println("STUN failed: likely detections="+countLikely+" unlikely detections="+countUnlikely); return null; } private DetectedIP convert(DiscoveryInfo info) { InetAddress addr = info.getPublicIP(); if(addr == null || addr.isLinkLocalAddress() || addr.isSiteLocalAddress()) return null; if(info.isError()) return null; if(info.isOpenAccess()) return new DetectedIP(addr, DetectedIP.FULL_INTERNET); if(info.isBlockedUDP()) return new DetectedIP(addr, DetectedIP.NO_UDP); if(info.isFullCone()) return new DetectedIP(addr, DetectedIP.FULL_CONE_NAT); if(info.isRestrictedCone()) return new DetectedIP(addr, DetectedIP.RESTRICTED_CONE_NAT); if(info.isPortRestrictedCone()) return new DetectedIP(addr, DetectedIP.PORT_RESTRICTED_NAT); if(info.isSymmetricCone()) return new DetectedIP(addr, DetectedIP.SYMMETRIC_NAT); if(info.isSymmetricUDPFirewall()) return new DetectedIP(addr, DetectedIP.SYMMETRIC_UDP_FIREWALL); return new DetectedIP(addr, DetectedIP.NOT_SUPPORTED); } public DetectedIP[] getAddress() { Enumeration ifaces; try { ifaces = NetworkInterface.getNetworkInterfaces(); } catch (SocketException e1) { System.err.println("Caught "+e1); e1.printStackTrace(); return null; } while (ifaces.hasMoreElements()) { if(WrapperManager.hasShutdownHookBeenTriggered()) return null; NetworkInterface iface = ifaces.nextElement(); Enumeration iaddresses = iface.getInetAddresses(); while (iaddresses.hasMoreElements()) { InetAddress iaddress = iaddresses.nextElement(); if (!iaddress.isLoopbackAddress() && !iaddress.isLinkLocalAddress()) { Thread detector = new DetectorThread(iaddress); synchronized(this) { detectors.add(detector); } try { detector.start(); } catch (Throwable t) { synchronized(this) { detectors.remove(detector); } } } } } synchronized(this) { while(true) { if(detectors.isEmpty()) { if(detected.isEmpty()) { System.err.println("STUN failed to detect IP addresses"); return null; } DetectedIP[] ips = (DetectedIP[]) detected.toArray(new DetectedIP[detected.size()]); return ips; } try { wait(); } catch (InterruptedException e) { // Check whether finished } } } } private final HashSet detected = new HashSet(); private final HashSet detectors = new HashSet(); class DetectorThread extends Thread { DetectorThread(InetAddress addr) { this.startAddress = addr; this.setDaemon(true); this.setName("STUN IP detector for "+addr); } final InetAddress startAddress; public void run() { DetectedIP[] ip; try { ip = runTest(startAddress); NetworkInterface nif = NetworkInterface.getByInetAddress(startAddress); int mtu = -1; if(nif != null) { try { Class c = nif.getClass(); Method m = c.getDeclaredMethod("getMTU", new Class[0]); if(m != null) { Integer iMTU = (Integer) m.invoke(nif, new Object[0]); if(iMTU != null) { mtu = iMTU.intValue(); System.err.println("Found interface MTU: "+nif.getName()+" : "+mtu); } } } catch (Throwable t) { System.err.println("Trying to access 1.6 getMTU(), caught "+t); } } if(ip != null) { for(int i=0; i