diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java index 294ea3dee..d33e0f265 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java @@ -27,6 +27,8 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable protected List dests; private static final long DEFAULT_READ_TIMEOUT = 5*60*1000; // -1 protected long readTimeout = DEFAULT_READ_TIMEOUT; + /** this is the pong response the client expects for their last ping. at least, i hope so... */ + private String _expectedPong; /** * @throws IllegalArgumentException if the I2PTunnel does not contain @@ -44,6 +46,8 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable l, notifyThis, "IRCHandler " + (++__clientId), tunnel); + + _expectedPong = null; StringTokenizer tok = new StringTokenizer(destinations, ","); dests = new ArrayList(1); @@ -147,6 +151,8 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable break; if(inmsg.endsWith("\r")) inmsg=inmsg.substring(0,inmsg.length()-1); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("in: [" + inmsg + "]"); String outmsg = inboundFilter(inmsg); if(outmsg!=null) { @@ -217,9 +223,41 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable break; if(inmsg.endsWith("\r")) inmsg=inmsg.substring(0,inmsg.length()-1); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("out: [" + inmsg + "]"); String outmsg = outboundFilter(inmsg); if(outmsg!=null) { + if (outmsg.indexOf("PING") >= 0) { + // 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) + // the PONG to the former seems to be "PONG 127.0.0.1", while the PONG to the later is + // ":irc.freshcoffee.i2p PONG irc.freshcoffe.i2p :1234567890". + // We don't want to send them our proxy's IP address, so we need to rewrite the PING + // sent to the server, but when we get a PONG back, use what we expected, rather than + // what they sent. + // + // Yuck. + StringTokenizer tok = new StringTokenizer(inmsg, " "); + int tokens = tok.countTokens(); + if ( (tokens <= 2) || (tokens == 3) ) { // "PING nonce" or "PING nonce serverIP" + tok.nextToken(); // skip + //_expectedPong = "PONG 127.0.0.1 :" + tok.nextToken(); + _expectedPong = "PONG " + tok.nextToken(); + } else { + // if it isn't one of those two, we will filter out all PONGs, which means + // the client will fail. whee! + if (_log.shouldLog(Log.ERROR)) + _log.error("IRC client sent a PING we don't understand (\"" + inmsg + "\"), so we're filtering it"); + _expectedPong = null; + } + if (_log.shouldLog(Log.WARN)) { + _log.warn("outbound rewritten PING: "+outmsg + ", waiting for [" + _expectedPong + "]"); + _log.warn(" - outbound was: "+inmsg); + } + } + if(!inmsg.equals(outmsg)) { if (_log.shouldLog(Log.WARN)) { _log.warn("outbound FILTERED: "+outmsg); @@ -256,7 +294,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable * */ - public static String inboundFilter(String s) { + public String inboundFilter(String s) { String field[]=s.split(" ",4); String command; @@ -264,8 +302,8 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable final String[] allowedCommands = { "NOTICE", - "PING", - "PONG", + //"PING", + //"PONG", "MODE", "JOIN", "NICK", @@ -293,6 +331,21 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable new Integer(command); return s; } catch(NumberFormatException nfe){} + + + if ("PING".equals(command)) + return "PING 127.0.0.1"; // no way to know what the ircd to i2ptunnel server con is, so localhost works + if ("PONG".equals(command)) { + // Turn the received ":irc.freshcoffee.i2p PONG irc.freshcoffee.i2p :127.0.0.1" + // into ":127.0.0.1 PONG 127.0.0.1 " so that the caller can append the client's extra parameter + // though, does 127.0.0.1 work for irc clients connecting remotely? and for all of them? sure would + // be great if irc clients actually followed the RFCs here, but i guess thats too much to ask. + // If we haven't PINGed them, or the PING we sent isn't something we know how to filter, this + // is null. + String pong = _expectedPong; + _expectedPong = null; + return pong; + } // Allow all allowedCommands for(int i=0;i