diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java index bfe311d3c..97dda6a8b 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java @@ -61,6 +61,7 @@ import net.i2p.data.Base64; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Destination; +import net.i2p.i2ptunnel.socks.I2PSOCKSIRCTunnel; import net.i2p.i2ptunnel.socks.I2PSOCKSTunnel; import net.i2p.i2ptunnel.streamr.StreamrConsumer; import net.i2p.i2ptunnel.streamr.StreamrProducer; @@ -895,6 +896,39 @@ public class I2PTunnel implements Logging, EventDispatcher { } } + + /** + * Run an SOCKS IRC tunnel on the given port number + * @since 0.7.12 + */ + public void runSOCKSIRCTunnel(String args[], Logging l) { + if (args.length >= 1 && args.length <= 2) { + int _port = -1; + try { + _port = Integer.parseInt(args[0]); + } catch (NumberFormatException nfe) { + l.log("invalid port"); + _log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe); + notifyEvent("sockstunnelTaskId", Integer.valueOf(-1)); + return; + } + + boolean isShared = false; + if (args.length > 1) + isShared = "true".equalsIgnoreCase(args[1].trim()); + + ownDest = !isShared; + I2PTunnelTask task; + task = new I2PSOCKSIRCTunnel(_port, l, ownDest, (EventDispatcher) this, this); + addtask(task); + notifyEvent("sockstunnelTaskId", Integer.valueOf(task.getId())); + } else { + l.log("sockstunnel "); + l.log(" creates a tunnel that distributes SOCKS requests."); + notifyEvent("sockstunnelTaskId", Integer.valueOf(-1)); + } + } + /** * Streamr client * diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java index 007652673..3da9e5fd7 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java @@ -82,10 +82,10 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable try { i2ps = createI2PSocket(clientDest); i2ps.setReadTimeout(readTimeout); - StringBuilder expectedPong = new StringBuilder(); - Thread in = new I2PAppThread(new IrcInboundFilter(s,i2ps, expectedPong), "IRC Client " + __clientId + " in"); + StringBuffer expectedPong = new StringBuffer(); + Thread in = new I2PAppThread(new IrcInboundFilter(s,i2ps, expectedPong), "IRC Client " + __clientId + " in", true); in.start(); - Thread out = new I2PAppThread(new IrcOutboundFilter(s,i2ps, expectedPong), "IRC Client " + __clientId + " out"); + Thread out = new I2PAppThread(new IrcOutboundFilter(s,i2ps, expectedPong), "IRC Client " + __clientId + " out", true); out.start(); } catch (Exception ex) { if (_log.shouldLog(Log.ERROR)) @@ -117,13 +117,13 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable /************************************************************************* * */ - private class IrcInboundFilter implements Runnable { + public static class IrcInboundFilter implements Runnable { private Socket local; private I2PSocket remote; - private StringBuilder expectedPong; + private StringBuffer expectedPong; - IrcInboundFilter(Socket _local, I2PSocket _remote, StringBuilder pong) { + public IrcInboundFilter(Socket _local, I2PSocket _remote, StringBuffer pong) { local=_local; remote=_remote; expectedPong=pong; @@ -191,13 +191,13 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable /************************************************************************* * */ - private class IrcOutboundFilter implements Runnable { + public static class IrcOutboundFilter implements Runnable { private Socket local; private I2PSocket remote; - private StringBuilder expectedPong; + private StringBuffer expectedPong; - IrcOutboundFilter(Socket _local, I2PSocket _remote, StringBuilder pong) { + public IrcOutboundFilter(Socket _local, I2PSocket _remote, StringBuffer pong) { local=_local; remote=_remote; expectedPong=pong; @@ -266,7 +266,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable * */ - public String inboundFilter(String s, StringBuilder expectedPong) { + public static String inboundFilter(String s, StringBuffer expectedPong) { String field[]=s.split(" ",4); String command; @@ -353,7 +353,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable return null; } - public String outboundFilter(String s, StringBuilder expectedPong) { + public static String outboundFilter(String s, StringBuffer expectedPong) { String field[]=s.split(" ",3); String command; @@ -378,7 +378,8 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable "KICK", "HELPME", "RULES", - "TOPIC" + "TOPIC", + "ISON" // jIRCii uses this for a ping (response is 303) }; if(field[0].length()==0) @@ -390,7 +391,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable command = field[0].toUpperCase(); - if ("PING".equalsIgnoreCase(command)) { + if ("PING".equals(command)) { // Most clients just send a PING and are happy with any old PONG. Others, // like BitchX, actually expect certain behavior. It sends two different pings: // "PING :irc.freshcoffee.i2p" and "PING 1234567890 127.0.0.1" (where the IP is the proxy) @@ -426,19 +427,19 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable return rv; } - if ("PONG".equalsIgnoreCase(command)) + if ("PONG".equals(command)) return "PONG 127.0.0.1"; // no way to know what the ircd to i2ptunnel server con is, so localhost works // Allow all allowedCommands for(int i=0;i SOCKSIRCTunnel"); + } + + /** + * Same as in I2PSOCKSTunnel, but run the filters from I2PTunnelIRCClient + * instead of I2PTunnelRunner + */ + @Override + protected void clientConnectionRun(Socket s) { + try { + _log.error("SOCKS IRC Tunnel Start"); + SOCKSServer serv = SOCKSServerFactory.createSOCKSServer(s); + Socket clientSock = serv.getClientSocket(); + I2PSocket destSock = serv.getDestinationI2PSocket(this); + StringBuffer expectedPong = new StringBuffer(); + Thread in = new I2PAppThread(new I2PTunnelIRCClient.IrcInboundFilter(clientSock, destSock, expectedPong), "SOCKS IRC Client " + (++__clientId) + " in", true); + in.start(); + Thread out = new I2PAppThread(new I2PTunnelIRCClient.IrcOutboundFilter(clientSock, destSock, expectedPong), "SOCKS IRC Client " + __clientId + " out", true); + out.start(); + } catch (SOCKSException e) { + _log.error("Error from SOCKS connection", e); + closeSocket(s); + } + } +} diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java index cc397c414..103f6a945 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java @@ -89,10 +89,10 @@ public class SOCKS5Server extends SOCKSServer { int method = Method.NO_ACCEPTABLE_METHODS; for (int i = 0; i < nMethods; ++i) { - method = in.readByte() & 0xff; - if (method == Method.NO_AUTH_REQUIRED) { + int meth = in.readByte() & 0xff; + if (meth == Method.NO_AUTH_REQUIRED) { // That's fine, we do support this method - break; + method = meth; } } @@ -119,7 +119,7 @@ public class SOCKS5Server extends SOCKSServer { int socksVer = in.readByte() & 0xff; if (socksVer != SOCKS_VERSION_5) { _log.debug("error in SOCKS5 request (protocol != 5? wtf?)"); - throw new SOCKSException("Invalid protocol version in request"); + throw new SOCKSException("Invalid protocol version in request: " + socksVer); } int command = in.readByte() & 0xff; diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java index ac1f7c77f..cc9909877 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java @@ -349,6 +349,7 @@ public class IndexBean { return ( ("client".equals(type)) || ("httpclient".equals(type)) || ("sockstunnel".equals(type)) || + ("socksirctunnel".equals(type)) || ("connectclient".equals(type)) || ("streamrclient".equals(type)) || ("ircclient".equals(type))); @@ -385,6 +386,7 @@ public class IndexBean { else if ("server".equals(internalType)) return _("Standard server"); else if ("httpserver".equals(internalType)) return _("HTTP server"); else if ("sockstunnel".equals(internalType)) return _("SOCKS 4/4a/5 proxy"); + else if ("socksirctunnel".equals(internalType)) return _("SOCKS IRC proxy"); else if ("connectclient".equals(internalType)) return _("CONNECT/SSL/HTTPS proxy"); else if ("ircserver".equals(internalType)) return _("IRC server"); else if ("streamrclient".equals(internalType)) return _("Streamr client"); diff --git a/apps/i2ptunnel/jsp/index.jsp b/apps/i2ptunnel/jsp/index.jsp index 3c356fefd..bcb4c6679 100644 --- a/apps/i2ptunnel/jsp/index.jsp +++ b/apps/i2ptunnel/jsp/index.jsp @@ -250,7 +250,8 @@ } %> - <% if (!"sockstunnel".equals(indexBean.getInternalType(curClient))) { %> + <% if (!("sockstunnel".equals(indexBean.getInternalType(curClient)) || + "socksirctunnel".equals(indexBean.getInternalType(curClient)))) { %>