Tunnel control now lets you easily create client and server tunnels

pull/2/head
knaccc 5 years ago
parent 9a0f72d3d0
commit 7b6a21c15a

@ -63,3 +63,23 @@ Press Ctrl-C to gracefully shut down the router (or send the SIGINT signal to th
## Check that the I2P router is running and that it is listening for SAM connections
`fuser 7656/tcp`
## Tunnel control
Listen for i2p connections and forward them to the specified host and port. Returns a newly created destination public key.
`dist/linux/router/bin/tunnel-control.sh server.create <host> <port>`
// Close the tunnel listening for connections on the specified port. Returns "OK".
`dist/linux/router/bin/tunnel-control.sh server.destroy <i2p destination public key>`
Create a tunnel that listens for connections on localhost and forwards connections over I2P to the specified destination public key. Returns a newly created localhost port number.
`dist/linux/router/bin/tunnel-control.sh client.create <i2p destination public key>`
Close the tunnel listening for connections on the specified port. Returns "OK".
`dist/linux/router/bin/tunnel-control.sh client.destroy <port>`
## Watch the I2P log for messages
`tail -f dist/linux/router/i2p.config/wrapper.log`

@ -8,6 +8,9 @@ $basedir/bin/import-packages.sh
# build the i2p project retrieved from the I2P repository
$basedir/bin/build-original-i2p.sh
# convert the imported JARs to modules, compile the Java source code in this project, and then use the jlink tool
# convert the jar files from an existing I2P build into modules suitable for use with jlink
$basedir/bin/convert-jars-to-modules.sh
# compile the Java source code in this project, and then use the jlink tool
# to build a zero-dependency platform-specific launcher
$basedir/bin/build-launcher.sh

@ -4,9 +4,6 @@ basedir=$(dirname $(dirname $(readlink -fm $0)))
source $basedir/bin/java-config.sh
# convert the jar files from an existing I2P build into modules suitable for use with jlink
$basedir/bin/convert-jars-to-modules.sh
# compile the Main class that starts the I2P router and SAM listener
echo "*** Compiling Main class"
$JAVA_HOME/bin/javac --module-path import/lib -d target/classes $(find src -name '*.java')
@ -29,8 +26,10 @@ echo "*** Performing jlink (Windows)"
$JAVA_HOME/bin/jlink --module-path $basedir/import/jdks/win/jdk-${JDK_VERSION}/jmods:target/modules:target/org.getmonero.i2p.embedded.jar --add-modules org.getmonero.i2p.embedded --output dist/win/router --strip-debug --compress 2 --no-header-files --no-man-pages
cp $basedir/resources/launch.sh $basedir/dist/linux/router/bin/
cp $basedir/resources/launch.sh $basedir/dist/mac/router/bin/
for i in linux mac; do
cp $basedir/resources/launch.sh $basedir/dist/$i/router/bin/
cp $basedir/resources/tunnel-control.sh $basedir/dist/$i/router/bin/
done
cp $basedir/resources/launch.bat $basedir/dist/win/router/bin/
for i in linux mac win; do cp -r $basedir/import/i2p.base $basedir/dist/$i/router/; done

@ -16,7 +16,7 @@ cd ..
# copy the jars that we're going to modularize
rm -fr $basedir/import/lib
mkdir -p $basedir/import/lib
for i in i2p.jar mstreaming.jar router.jar sam.jar streaming.jar; do cp $basedir/import/i2p.i2p/build/$i $basedir/import/lib/; done
for i in i2ptunnel.jar i2p.jar mstreaming.jar router.jar sam.jar streaming.jar; do cp $basedir/import/i2p.i2p/build/$i $basedir/import/lib/; done
# build a minimal i2p.base dir
rm -fr $basedir/import/i2p.base

@ -0,0 +1,3 @@
#!/bin/bash
exec 3<>/dev/tcp/localhost/30000; echo "$1 $2 $3" >&3; cat <&3

@ -4,5 +4,6 @@ module org.getmonero.i2p.embedded {
requires streaming;
requires router;
requires sam;
requires i2ptunnel;
requires jdk.crypto.ec;
}

@ -71,6 +71,9 @@ public class Main {
ClientAppManager mgr = new ClientAppManagerImpl(context);
SAMBridge samBridge = new SAMBridge(context, mgr, args);
samBridge.startup();
new Thread(new TunnelControl(new File(new File(p.getProperty("i2p.dir.config")), "tunnel"))).start();
}
catch (Exception e) {
e.printStackTrace();

@ -0,0 +1,114 @@
package org.getmonero.i2p.embedded;
import net.i2p.data.Base64;
import net.i2p.i2ptunnel.I2PTunnel;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
public class TunnelControl implements Runnable {
private Map<Integer, I2PTunnel> clientTunnels = new HashMap<>();
private Map<String, I2PTunnel> serverTunnels = new HashMap<>();
private int clientPortSeq = 30000;
private int serverSeq = 0;
private String tunnelConfigDirPrefix;
public TunnelControl(File tunnelConfigDir) {
tunnelConfigDir.delete();
tunnelConfigDir.mkdir();
this.tunnelConfigDirPrefix = tunnelConfigDir.getAbsolutePath() + File.separator;
}
@Override
public void run() {
// listen for socket connections to the tunnel controller.
// listen for the commands on port 30000:
// server.create <host> <port> // returns a newly created destination public key, which will listen for i2p connections and forward them to the specified host and port
// server.destroy <i2p destination public key> // closes the tunnel listening for connections on the specified port, and returns OK
// client.create <i2p destination public key> // returns a newly created localhost port number, where connections will be sent over I2P to the destination public key
// client.destroy <port> // closes the tunnel listening for connections on the specified port, and returns OK
//
// send a command with bash: exec 3<>/dev/tcp/localhost/30000; echo "server.create localhost 80" >&3; cat <&3
//
try (var listener = new ServerSocket(clientPortSeq++, 0, InetAddress.getLoopbackAddress())) {
while (true) {
try (var socket = listener.accept()) {
var out = new PrintWriter(socket.getOutputStream(), true);
var in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
var args = in.readLine().split(" ");
if(args[0].equals("server.create")) {
String destHost = args[1];
String destPort = args[2];
String seckeyPath = tunnelConfigDirPrefix + "seckey."+serverSeq+".dat";
String pubkeyPath = tunnelConfigDirPrefix + "pubkey."+serverSeq+".dat";
serverSeq++;
new I2PTunnel(new String[]{"-die", "-nocli", "-e", "genkeys " + seckeyPath + " " + pubkeyPath});
String destPubKey = Base64.encode(Files.readAllBytes(new File(pubkeyPath).toPath()));
// listen using the I2P server keypair, and forward incoming connections to a destination and port
new Thread() {
@Override
public void run() {
I2PTunnel t = new I2PTunnel(new String[]{"-die", "-nocli", "-e", "server "+destHost+" "+destPort+" " + seckeyPath});
serverTunnels.put(destPubKey, t);
}
}.start();
out.println(destPubKey);
}
else if(args[0].equals("server.destroy")) {
String destPubKey = args[1];
new Thread() {
@Override
public void run() {
var t = serverTunnels.get(destPubKey);
serverTunnels.remove(destPubKey);
t.runClose(new String[]{"forced", "all"}, t);
}
}.start();
out.println("OK");
}
else if(args[0].equals("client.create")) {
String destPubKey = args[1];
int port = clientPortSeq++;
new Thread() {
@Override
public void run() {
var t = new I2PTunnel(new String[]{"-die", "-nocli", "-e", "config localhost 7654", "-e", "client " + port + " " + destPubKey});
clientTunnels.put(port, t);
}
}.start();
out.println(port);
}
if(args[0].equals("client.destroy")) {
int port = Integer.parseInt(args[1]);
new Thread() {
@Override
public void run() {
var t = clientTunnels.get(port);
clientTunnels.remove(port);
t.runClose(new String[]{"forced", "all"}, t);
}
}.start();
out.println("OK");
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
Loading…
Cancel
Save