From 540c1a3c25367b15f3d7458c9727a02cfb4a09d2 Mon Sep 17 00:00:00 2001 From: knaccc Date: Sat, 23 Mar 2019 23:38:47 +0000 Subject: [PATCH] inform user of the port to open in their firewall version available check fix --- README.md | 4 + .../getmonero/i2p/zero/gui/Controller.java | 10 ++- .../src/org/getmonero/i2p/zero/Main.java | 3 +- .../org/getmonero/i2p/zero/RouterWrapper.java | 8 +- .../org/getmonero/i2p/zero/TunnelControl.java | 5 ++ .../org/getmonero/i2p/zero/UpdateCheck.java | 77 ++++++++++++------- .../src/org/getmonero/i2p/zero/VERSION | 2 +- 7 files changed, 76 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 2ec8fc6..5d14661 100755 --- a/README.md +++ b/README.md @@ -159,6 +159,10 @@ specified host and port. Note that the base 32 I2P destination address determini `tunnel-control.sh sam.create` +#### Get the external port randomly assigned to this router when first run, which the firewall should allow incoming UDP and TCP connections on. Returns the port number. + +`tunnel-control.sh router.externalPort` + ## Watch the I2P log for messages diff --git a/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Controller.java b/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Controller.java index 811f326..9f10897 100644 --- a/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Controller.java +++ b/org.getmonero.i2p.zero.gui/src/org/getmonero/i2p/zero/gui/Controller.java @@ -96,8 +96,6 @@ public class Controller { @FXML private void initialize() { - helpTextArea.setText("You are running I2P-zero version " + UpdateCheck.currentVersion + "\n\n" + helpTextArea.getText()); - DirectoryChooser directoryChooser = new DirectoryChooser(); typeCol.setCellValueFactory(new PropertyValueFactory("type")); @@ -260,7 +258,7 @@ public class Controller { if(masterState) { masterToggle.setImage(new Image("org/getmonero/i2p/zero/gui/toggle-on.png")); statusLabel.setVisible(true); - routerWrapper.start(); + routerWrapper.start(()->{}); listenForTunnelChanges(); tunnelAddButton.setDisable(false); } @@ -364,7 +362,11 @@ public class Controller { alert.show(); }); }); - routerWrapper.start(); + routerWrapper.start(()->{ + helpTextArea.setText("You are running I2P-zero version " + UpdateCheck.currentVersion + "\n\n" + + "For best performance, please open port " + routerWrapper.routerExternalPort + " on your firewall for incoming UDP and TCP connections. This port has been randomly assigned to you. For privacy reasons, please do not share this port with others.\n\n" + + helpTextArea.getText()); + }); } diff --git a/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/Main.java b/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/Main.java index d286555..b972af5 100644 --- a/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/Main.java +++ b/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/Main.java @@ -40,7 +40,8 @@ public class Main { RouterWrapper routerWrapper = new RouterWrapper(p, ()->{ Main.consoleOut.println("**** A new version of I2P-zero is available at https://github.com/i2p-zero/i2p-zero - Please keep your software up-to-date, as it will enhance your privacy and keep you safe from vulnerabilities"); }); - routerWrapper.start(); + + routerWrapper.start(()->Main.consoleOut.println("For best performance, please open port " + routerWrapper.routerExternalPort + " on your firewall for incoming UDP and TCP connections. This port has been randomly assigned to you. For privacy reasons, please do not share this port with others.")); Runtime.getRuntime().addShutdownHook(new Thread(()->routerWrapper.stop(true))); diff --git a/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/RouterWrapper.java b/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/RouterWrapper.java index 55dd2b9..39ca85f 100644 --- a/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/RouterWrapper.java +++ b/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/RouterWrapper.java @@ -29,6 +29,8 @@ public class RouterWrapper { private File i2PBaseDir; private Runnable updateAvailableCallback; + public int routerExternalPort; + public RouterWrapper(Properties routerProperties, Runnable updateAvailableCallback) { this.routerProperties = routerProperties; this.updateAvailableCallback = updateAvailableCallback; @@ -72,7 +74,7 @@ public class RouterWrapper { return started; } - public void start() { + public void start(Runnable routerIsAliveCallback) { new Thread(()-> { if(started) return; @@ -99,6 +101,10 @@ public class RouterWrapper { System.out.println("I2P router now running"); + File routerConfigFile = new File(i2PBaseDir, "router.config"); + routerExternalPort = Integer.parseInt(Files.lines(routerConfigFile.toPath()).filter(s->s.startsWith("i2np.udp.port=")).findFirst().get().split("=")[1]); + new Thread(routerIsAliveCallback).start(); + tunnelControl = new TunnelControl(this, i2PConfigDir, new File(i2PConfigDir, "tunnelTemp")); new Thread(tunnelControl).start(); diff --git a/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/TunnelControl.java b/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/TunnelControl.java index 2744f91..7d46f60 100644 --- a/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/TunnelControl.java +++ b/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/TunnelControl.java @@ -628,6 +628,11 @@ public class TunnelControl implements Runnable { break; } + case "router.externalPort": { + out.println(routerWrapper.routerExternalPort); + break; + } + case "sam.create": { String[] samArgs = new String[]{"sam.keys", "127.0.0.1", "7656", "i2cp.tcp.host=127.0.0.1", "i2cp.tcp.port=7654"}; I2PAppContext context = routerWrapper.getRouter().getContext(); diff --git a/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/UpdateCheck.java b/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/UpdateCheck.java index d33d113..d2e0230 100644 --- a/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/UpdateCheck.java +++ b/org.getmonero.i2p.zero/src/org/getmonero/i2p/zero/UpdateCheck.java @@ -10,6 +10,8 @@ import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; import java.util.Scanner; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -18,39 +20,56 @@ public class UpdateCheck { public static final String currentVersion = new Scanner(RouterWrapper.class.getResourceAsStream("VERSION")).useDelimiter("\\n").next(); + private static boolean isNewerVersionAvailable(String currentVersion, String versionAvailable) { + int currentMajor = Integer.parseInt(currentVersion.split(".")[0]); + int currentMinor = Integer.parseInt(currentVersion.split(".")[1]); + int availableMajor = Integer.parseInt(versionAvailable.split(".")[0]); + int availableMinor = Integer.parseInt(versionAvailable.split(".")[1]); + if(availableMajor>currentMajor) return true; + if(availableMajorcurrentMinor) return true; + return false; + } + public static void scheduleUpdateCheck(File i2PConfigDir, Router router, Runnable updateAvailableCallback) { - File updateAvailableFile = new File(i2PConfigDir, "updateAvailable"); - if(updateAvailableFile.exists()) { - updateAvailableCallback.run(); - } - else { + try { + File versionAvailableFile = new File(i2PConfigDir, "versionAvailable"); + if(!versionAvailableFile.exists()) { + Files.write(versionAvailableFile.toPath(), currentVersion.getBytes(), StandardOpenOption.CREATE); + } - // schedule next check randomly in the next 48 hrs. On average, this call pattern will result in a check every 24 hrs. - CompletableFuture.delayedExecutor((long) (Math.random()*3600*24*2), TimeUnit.SECONDS).execute(() -> { - if(lookupUpdateAvailable(router)) { - try { - // create an empty file to indicate an update is available, so in future we don't have to keep querying the server - updateAvailableFile.createNewFile(); - } - catch (Exception e) { - e.printStackTrace(); + String versionAvailable = Files.readString(versionAvailableFile.toPath()); + if(isNewerVersionAvailable(currentVersion, versionAvailable)) { + updateAvailableCallback.run(); + } + else { + + // schedule next check randomly in the next 48 hrs. On average, this call pattern will result in a check every 24 hrs. + CompletableFuture.delayedExecutor((long) (Math.random()*3600*24*2), TimeUnit.SECONDS).execute(() -> { + String versionAvailableLookup = lookupVersionAvailable(router); + if(versionAvailableLookup!=null) { + try { + // create an empty file to indicate an update is available, so in future we don't have to keep querying the server + Files.write(versionAvailableFile.toPath(), versionAvailableLookup.getBytes(), StandardOpenOption.CREATE); + } catch (Exception e) { + e.printStackTrace(); + } } - updateAvailableCallback.run(); - } - else { - // only check again if no update available yet scheduleUpdateCheck(i2PConfigDir, router, updateAvailableCallback); - } - }); + }); + } + } + catch (Exception e) { + e.printStackTrace(); } } - public static boolean lookupUpdateAvailable(Router router) { + public static String lookupVersionAvailable(Router router) { try { - String versionAvailable = null; + String sanitizedVersionAvailable = null; String host = "77ypf3rahyjegncradypnyotvn6fhq7sobhwe2gs5a2hdiwehwjq.b32.i2p"; Destination dest = router.getContext().namingService().lookup(host, null, null); I2PSocketManager mgr = I2PSocketManagerFactory.createManager(); @@ -66,15 +85,21 @@ public class UpdateCheck { while ((line = br.readLine()) != null) { if (line.equals("")) break; } - versionAvailable = br.readLine(); + String rawVersionAvailable = br.readLine(); + // sanitize, just in case the update notification server is compromised + if(rawVersionAvailable.length()>10) return null; + String allowedChars = "0123456789."; + sanitizedVersionAvailable = ""; + for(var i=0; i0) sanitizedVersionAvailable += rawVersionAvailable.charAt(i); + } } br.close(); - if(versionAvailable==null) return false; - else return Float.parseFloat(currentVersion)