package plugins.CENO.Backbone; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.util.Arrays; import java.util.List; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import plugins.CENO.Configuration; import plugins.CENO.Version; import plugins.CENO.FreenetInterface.NodeInterface; import freenet.client.InsertException; import freenet.client.async.PersistenceDisabledException; import freenet.clients.http.ConnectionsToadlet.PeerAdditionReturnCodes; import freenet.io.comm.PeerParseException; import freenet.io.comm.ReferenceSignatureVerificationException; import freenet.keys.FreenetURI; import freenet.node.DarknetPeerNode; import freenet.node.DarknetPeerNode.FRIEND_TRUST; import freenet.node.DarknetPeerNode.FRIEND_VISIBILITY; import freenet.node.FSParseException; import freenet.node.Node; import freenet.node.PeerNode; import freenet.pluginmanager.FredPlugin; import freenet.pluginmanager.FredPluginRealVersioned; import freenet.pluginmanager.FredPluginThreadless; import freenet.pluginmanager.FredPluginVersioned; import freenet.pluginmanager.PluginRespirator; import freenet.support.Logger; import freenet.support.SimpleFieldSet; /** * CENOBackbone plugin for Freenet * * Its main purpose is to help route CENOBrdige packets * faster to the area they should arrive to, based on the * phenomenon of Small World Routing. * * Once the plugin is loaded, it will add as friend the * bridge node (using the node reference in the resources) * and send a Freemail to the bridge with its own reference, * so that the bridge can add it back as a friend. * Trust is set to HIGH and other friends of the Backbone * node won't be able to see either the name or the node * reference of the Bridge node. * * It is recommended that the Backbone nodes stay connected * for as long as possible and are given a high * bandwidth limit. The most straightforward way to spin * a backbone router is to use the CENOBackboneBox. * Also, you are encouraged to allocate enough space for the * client cache, because it will contribute to the longevity * and faster access of the bundles inserted by the CENOBridge. * * This plugin has a strong dependency on the WebOfTrust * and Freemail official Freenet plugins. */ public class CENOBackbone implements FredPlugin, FredPluginVersioned, FredPluginRealVersioned, FredPluginThreadless { private static final Version VERSION = new Version(Version.PluginType.BACKBONE); //public static final String BRIDGE_KEY = "SSK@mlfLfkZmWIYVpKbsGSzOU~-XuPp~ItUhD8GlESxv8l4,tcB-IHa9c4wpFudoSm0k-iTaiE~INdeQXvcYP2M1Nec,AQACAAE/"; what's up? public static Node node; public static NodeInterface nodeInterface; private NodeRefHelper nodeRefHelper; public static Configuration initConfig; private static final String CONFIGPATH = ".CENO/bridge.properties"; public static final String ANNOUNCER_PATH = "CENO-Backbone"; ScheduledExecutorService scheduledExecutorService; ScheduledFuture<?> scheduleSend; public void runPlugin(PluginRespirator pr) { node = pr.getNode(); nodeRefHelper = new NodeRefHelper(node); // Read properties of the configuration file initConfig = new Configuration(CONFIGPATH); initConfig.readProperties(); // Add the bridge node reference in the resources as a friend PeerAdditionReturnCodes addBridgeResult = addFriendBridges(); if (addBridgeResult == PeerAdditionReturnCodes.ALREADY_IN_REFERENCE || addBridgeResult == PeerAdditionReturnCodes.OK) { Logger.normal(this, "Successfully added the node in bridgeref.txt resource file as friend."); } else { // Bridge node could not be added as a friend, the plugin will terminate and unload Logger.error(this, "Error while adding Bridge node as a friend, will terminate Backbone plugin..."); terminate(); } nodeInterface = new NodeInterface(pr.getNode(), pr); if (initConfig.getProperty("backboneAnnounceURI") == null || initConfig.getProperty("backboneAnnounceURI").isEmpty()) { //we are not told where to announce our existance Logger.warning(this, "backboneAnnounceURI is needed in order to inform the master bridge about our existance"); } else { //announce the descriptor in the uri //vmon: I don't think we need this we just can simply insert our descriptor in the given URI. /* Schedule a thread in order to Send a Freemail to the bridge node with the own node reference. * First attempt will be in a minute from plugin initialization, and if it fails, there will be * other attempts every 2 minutes till the Freemail is sent. For every failed attempt, we keep * an error-level entry in the log. */ //scheduledExecutorService = Executors.newScheduledThreadPool(1); //scheduleSend = scheduledExecutorService.scheduleWithFixedDelay(new RefSender(), 2, 1, TimeUnit.MINUTES); try { announceDescriptor(initConfig.getProperty("backboneAnnounceURI")); Logger.normal(this, "Successfully annouced our node reference to the bridges."); } catch(InsertException e) { Logger.warning(this, "failed to announce our descriptor to the CENO Bridge(s): "+ e.getMessage()); } } //store the node descriptor for later use try { nodeRefHelper.writeOwnRef(); } catch (IOException e) { Logger.error(this, "IO Exception while storing own reference resource file"); } } /** * Adds the node references in the resources * as friends to the node this plugin is loaded. * * @return the corresponding PeerAdditionReturnCode * indicating whether the bridges were added successfully * as friends */ private PeerAdditionReturnCodes addFriendBridges() { List<SimpleFieldSet> bridgeNodeFSList; try { bridgeNodeFSList = nodeRefHelper.readBridgeRefs(); } catch (IOException e) { Logger.error(this, "IO Exception while parsing bridge reference resource file"); return PeerAdditionReturnCodes.INTERNAL_ERROR; } //For now we are panincing if even we fail to add one of the bridges PeerNode pn; for(SimpleFieldSet bridgeNodeFS : bridgeNodeFSList) { try { pn = node.createNewDarknetNode(bridgeNodeFS, FRIEND_TRUST.HIGH, FRIEND_VISIBILITY.NO); ((DarknetPeerNode)pn).setPrivateDarknetCommentNote("CeNo Bridge"); } catch (FSParseException e) { return PeerAdditionReturnCodes.CANT_PARSE; } catch (PeerParseException e) { return PeerAdditionReturnCodes.CANT_PARSE; } catch (ReferenceSignatureVerificationException e){ return PeerAdditionReturnCodes.INVALID_SIGNATURE; } catch (Throwable t) { Logger.error(this, "Internal error adding reference :" + t.getMessage(), t); return PeerAdditionReturnCodes.INTERNAL_ERROR; } //if(Arrays.equals(pn.getPubKeyHash(), node.getDarknetPubKeyHash())) { if(Arrays.equals(pn.peerECDSAPubKeyHash, node.getDarknetPubKeyHash())) { //fred-next version Logger.warning(this, "The bridge node reference file belongs to this node."); //return PeerAdditionReturnCodes.TRY_TO_ADD_SELF; } if(!node.addPeerConnection(pn)) { Logger.warning(this, "The bridge node is already be friended."); //return PeerAdditionReturnCodes.ALREADY_IN_REFERENCE; } } return PeerAdditionReturnCodes.OK; } public String getVersion() { return VERSION.getVersion(); } public long getRealVersion() { return VERSION.getRealVersion(); } public void terminate() { if (scheduledExecutorService != null) { scheduledExecutorService.shutdownNow(); } } /** * inserts our node descriptor into the given URI * * @param backboneAnnounceURI the URI we are supposed to announce our descriptor in * * @throws InsertException in case insertion fails */ public void announceDescriptor(String backboneAnnounceURI) throws InsertException { //we read the ssk we are supposed to insert our node in from the Bridge.properties //Now Inserting our node descriptor into the SSK, shouldn't this be encrypted? //Maybe not as we are not disclosing the insertion URI try { FreenetURI insertURIconfig = new FreenetURI(backboneAnnounceURI); FreenetURI announcementURI = new FreenetURI("USK", ANNOUNCER_PATH, insertURIconfig.getRoutingKey(), insertURIconfig.getCryptoKey(), insertURIconfig.getExtra()); Logger.normal(this, "Inserting announcement freesite with USK: " + announcementURI.toString()); nodeInterface.insertSingleChunk(announcementURI, nodeRefHelper.getNodeRef(), nodeInterface.getVoidPutCallback( "Successfully inserted our node descriptor with URI: " + announcementURI, "")); } catch (MalformedURLException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (PersistenceDisabledException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }