Files
i2p.itoopie/apps/q/java/src/net/i2p/aum/I2PCat.java

453 lines
12 KiB
Java
Raw Normal View History

// I2P equivalent of 'netcat'
package net.i2p.aum;
import java.lang.*;
import java.io.*;
import java.util.*;
import java.net.*;
import net.i2p.*;
import net.i2p.client.*;
import net.i2p.client.naming.*;
import net.i2p.client.streaming.*;
import net.i2p.data.*;
import net.i2p.util.*;
/**
* A I2P equivalent of the much-beloved 'netcat' utility.
* This command-line utility can either connect to a remote
* destination, or listen on a private destination for incoming
* connections. Once a connection is established, input on stdin
* is sent to the remote peer, and anything received from the
* remote peer is printed to stdout
*/
public class I2PCat extends Thread
{
public I2PSocketManager socketManager;
public I2PServerSocket serverSocket;
public I2PSocket sessSocket;
public PrivDestination key;
public Destination dest;
public InputStream socketIn;
public OutputStream socketOutStream;
public OutputStreamWriter socketOut;
public SockInput rxThread;
protected static Log _log;
public static String defaultHost = "127.0.0.1";
public static int defaultPort = 7654;
/**
* a thread for reading from socket and displaying on stdout
*/
private class SockInput extends Thread {
InputStream _in;
protected Log _log;
public SockInput(InputStream i) {
_in = i;
}
public void run()
{
// the thread portion, receives incoming bytes on
// the socket input stream and spits them to stdout
byte [] ch = new byte[1];
print("Receiver thread listening...");
try {
while (true) {
//String line = DataHelper.readLine(socketIn);
if (_in.read(ch) != 1) {
print("failed to receive from socket");
break;
}
//System.out.println(line);
System.out.write(ch, 0, 1);
System.out.flush();
}
} catch (IOException e) {
e.printStackTrace();
print("Receiver thread crashed, terminating!!");
System.exit(1);
}
}
void print(String msg)
{
System.out.println("-=- I2PCat: "+msg);
if (_log != null) {
_log.debug(msg);
}
}
}
public I2PCat()
{
_log = new Log("I2PCat");
}
/**
* Runs I2PCat in server mode, listening on the given destination
* for one incoming connection. Once connection is established,
* copyies data between the remote peer and
* the local terminal console.
*/
public void runServer(String keyStr) throws IOException, DataFormatException
{
Properties props = new Properties();
props.setProperty("inbound.length", "0");
props.setProperty("outbound.length", "0");
props.setProperty("inbound.lengthVariance", "0");
props.setProperty("outbound.lengthVariance", "0");
// generate new key if needed
if (keyStr.equals("new")) {
try {
key = PrivDestination.newKey();
} catch (I2PException e) {
e.printStackTrace();
return;
} catch (IOException e) {
e.printStackTrace();
return;
}
print("Creating new server dest...");
socketManager = I2PSocketManagerFactory.createManager(key.getInputStream(), props);
print("Getting server socket...");
serverSocket = socketManager.getServerSocket();
print("Server socket created, ready to run...");
dest = socketManager.getSession().getMyDestination();
print("private key follows:");
System.out.println(key.toBase64());
print("dest follows:");
System.out.println(dest.toBase64());
}
else {
key = PrivDestination.fromBase64String(keyStr);
String dest64Abbrev = key.toBase64().substring(0, 16);
print("Creating server socket manager on dest "+dest64Abbrev+"...");
socketManager = I2PSocketManagerFactory.createManager(key.getInputStream(), props);
serverSocket = socketManager.getServerSocket();
print("Server socket created, ready to run...");
}
print("Awaiting client connection...");
I2PSocket sessSocket;
try {
sessSocket = serverSocket.accept();
} catch (I2PException e) {
e.printStackTrace();
return;
} catch (ConnectException e) {
e.printStackTrace();
return;
}
print("Got connection from client");
chat(sessSocket);
}
public void runClient(String destStr)
throws DataFormatException, IOException
{
runClient(destStr, defaultHost, defaultPort);
}
/**
* runs I2PCat in client mode, connecting to a remote
* destination then copying data between the remote peer and
* the local terminal console
*/
public void runClient(String destStr, String host, int port)
throws DataFormatException, IOException
{
// accept 'file:' prefix
if (destStr.startsWith("file:", 0))
{
String path = destStr.substring(5);
destStr = new SimpleFile(path, "r").read();
}
else if (destStr.length() < 255) {
// attempt hosts file lookup
I2PAppContext ctx = new I2PAppContext();
HostsTxtNamingService h = new HostsTxtNamingService(ctx);
Destination dest1 = h.lookup(destStr);
if (dest1 == null) {
usage("Cannot resolve hostname: '"+destStr+"'");
}
// successful lookup
runClient(dest1, host, port);
}
else {
// otherwise, bigger strings are assumed to be base64 dests
Destination dest = new Destination();
dest.fromBase64(destStr);
runClient(dest, host, port);
}
}
public void runClient(Destination dest) {
runClient(dest, "127.0.0.1", 7654);
}
/**
* An alternative constructor which accepts an I2P Destination object
*/
public void runClient(Destination dest, String host, int port)
{
this.dest = dest;
String destAbbrev = dest.toBase64().substring(0, 16)+"...";
print("Connecting via i2cp "+host+":"+port+" to destination "+destAbbrev+"...");
System.out.flush();
try {
// get a socket manager
socketManager = I2PSocketManagerFactory.createManager(host, port);
// get a client socket
print("socketManager="+socketManager);
sessSocket = socketManager.connect(dest);
} catch (I2PException e) {
e.printStackTrace();
return;
} catch (ConnectException e) {
e.printStackTrace();
return;
} catch (NoRouteToHostException e) {
e.printStackTrace();
return;
} catch (InterruptedIOException e) {
e.printStackTrace();
return;
}
print("Successfully connected!");
print("(Press Control-C to quit)");
// Perform console interaction
chat(sessSocket);
try {
sessSocket.close();
} catch (IOException e) {
e.printStackTrace();
return;
}
}
/**
* Launch the background thread to copy incoming data to stdout, then
* loop in foreground copying lines from stdin and sending them to remote peer
*/
public void chat(I2PSocket sessSocket) {
try {
socketIn = sessSocket.getInputStream();
socketOutStream = sessSocket.getOutputStream();
socketOut = new OutputStreamWriter(socketOutStream);
// launch receiver thread
start();
//launchRx();
while (true) {
String line = DataHelper.readLine(System.in);
print("sent: '"+line+"'");
socketOut.write(line+"\n");
socketOut.flush();
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
/**
* executes in a thread, receiving incoming bytes on
* the socket input stream and spitting them to stdout
*/
public void run()
{
byte [] ch = new byte[1];
print("Receiver thread listening...");
try {
while (true) {
//String line = DataHelper.readLine(socketIn);
if (socketIn.read(ch) != 1) {
print("failed to receive from socket");
break;
}
//System.out.println(line);
System.out.write(ch, 0, 1);
System.out.flush();
}
} catch (IOException e) {
e.printStackTrace();
print("Receiver thread crashed, terminating!!");
System.exit(1);
}
}
public void launchRx() {
rxThread = new SockInput(socketIn);
rxThread.start();
}
static void print(String msg)
{
System.out.println("-=- I2PCat: "+msg);
if (_log != null) {
_log.debug(msg);
}
}
public static void usage(String msg)
{
usage(msg, 1);
}
public static void usage(String msg, int ret)
{
System.out.println(msg);
usage(ret);
}
public static void usage(int ret)
{
System.out.print(
"This utility is an I2P equivalent of the standard *nix 'netcat' utility\n"+
"usage:\n"+
" net.i2p.aum.I2PCat [-h]\n"+
" - display this help\n"+
" net.i2p.aum.I2PCat dest [host [port]]\n"+
" - run in client mode, 'dest' should be one of:\n"+
" hostname.i2p - an I2P hostname listed in hosts.txt\n"+
" (only works with a hosts.txt in current directory)\n"+
" base64dest - a full base64 destination string\n"+
" file:b64filename - filename of a file containing base64 dest\n"+
" net.i2p.aum.I2PCat -l privkey\n"+
" - run in server mode, 'key' should be one of:\n"+
" base64privkey - a full base64 private key string\n"+
" file:b64filename - filename of a file containing base64 privkey\n"+
"\n"
);
System.exit(ret);
}
public static void main(String [] args) throws IOException, DataFormatException
{
int argc = args.length;
// barf if no args
if (argc == 0) {
usage("Missing argument");
}
// show help on request
if (args[0].equals("-h") || args[0].equals("--help")) {
usage(0);
}
// server or client?
if (args[0].equals("-l")) {
if (argc != 2) {
usage("Bad argument count");
}
new I2PCat().runServer(args[1]);
}
else {
// client mode - barf if not 1-3 args
if (argc < 1 || argc > 3) {
usage("Bad argument count");
}
try {
int port = defaultPort;
String host = defaultHost;
if (args.length > 1) {
host = args[1];
if (args.length > 2) {
port = new Integer(args[2]).intValue();
}
}
new I2PCat().runClient(args[0], host, port);
} catch (DataFormatException e) {
e.printStackTrace();
}
}
}
}