* I2PSOCKSIRCTunnel:
- New, for filtering IRC client traffic when using SOCKS * I2PTunnelIRCClient: - Make filter classes static and public for use by SOCKS - Eliminate redundant case conversion - Pass ISON message through (jIRCii uses it for pings) - Switch back to StringBuffer since it's used by 2 threads - Set daemon on filter threads * SOCKS5Server: - Fix handling of multiple authentication methods
This commit is contained in:
@ -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 <port>");
|
||||
l.log(" creates a tunnel that distributes SOCKS requests.");
|
||||
notifyEvent("sockstunnelTaskId", Integer.valueOf(-1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Streamr client
|
||||
*
|
||||
|
@ -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<allowedCommands.length;i++)
|
||||
{
|
||||
if(allowedCommands[i].equalsIgnoreCase(command))
|
||||
if(allowedCommands[i].equals(command))
|
||||
return s;
|
||||
}
|
||||
|
||||
// mIRC sends "NOTICE user :DCC Send file (IP)"
|
||||
// in addition to the CTCP version
|
||||
if("NOTICE".equalsIgnoreCase(command))
|
||||
if("NOTICE".equals(command))
|
||||
{
|
||||
String msg = field[2];
|
||||
if(msg.startsWith(":DCC "))
|
||||
@ -447,7 +448,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
|
||||
// Allow PRIVMSG, but block CTCP (except ACTION).
|
||||
if("PRIVMSG".equalsIgnoreCase(command) || "NOTICE".equalsIgnoreCase(command))
|
||||
if("PRIVMSG".equals(command) || "NOTICE".equals(command))
|
||||
{
|
||||
String msg;
|
||||
msg = field[2];
|
||||
@ -465,14 +466,16 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
return s;
|
||||
}
|
||||
|
||||
if("USER".equalsIgnoreCase(command)) {
|
||||
if("USER".equals(command)) {
|
||||
int idx = field[2].lastIndexOf(":");
|
||||
if(idx<0)
|
||||
return "USER user hostname localhost :realname";
|
||||
String realname = field[2].substring(idx+1);
|
||||
String ret = "USER "+field[1]+" hostname localhost :"+realname;
|
||||
return ret;
|
||||
} else if ("QUIT".equalsIgnoreCase(command)) {
|
||||
}
|
||||
|
||||
if ("QUIT".equals(command)) {
|
||||
return "QUIT :leaving";
|
||||
}
|
||||
|
||||
|
@ -144,6 +144,8 @@ public class TunnelController implements Logging {
|
||||
startIrcClient();
|
||||
} else if("sockstunnel".equals(type)) {
|
||||
startSocksClient();
|
||||
} else if("socksirctunnel".equals(type)) {
|
||||
startSocksIRCClient();
|
||||
} else if("connectclient".equals(type)) {
|
||||
startConnectClient();
|
||||
} else if ("client".equals(type)) {
|
||||
@ -211,6 +213,14 @@ public class TunnelController implements Logging {
|
||||
_tunnel.runSOCKSTunnel(new String[] { listenPort, sharedClient }, this);
|
||||
}
|
||||
|
||||
/** @since 0.7.12 */
|
||||
private void startSocksIRCClient() {
|
||||
setListenOn();
|
||||
String listenPort = getListenPort();
|
||||
String sharedClient = getSharedClient();
|
||||
_tunnel.runSOCKSIRCTunnel(new String[] { listenPort, sharedClient }, this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Streamr client is a UDP server, use the listenPort field for targetPort
|
||||
* and the listenOnInterface field for the targetHost
|
||||
|
@ -0,0 +1,62 @@
|
||||
/* I2PSOCKSTunnel is released under the terms of the GNU GPL,
|
||||
* with an additional exception. For further details, see the
|
||||
* licensing terms in I2PTunnel.java.
|
||||
*
|
||||
* Copyright (c) 2004 by human
|
||||
*/
|
||||
package net.i2p.i2ptunnel.socks;
|
||||
|
||||
import java.net.Socket;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.i2ptunnel.I2PTunnel;
|
||||
import net.i2p.i2ptunnel.I2PTunnelIRCClient;
|
||||
import net.i2p.i2ptunnel.Logging;
|
||||
import net.i2p.util.EventDispatcher;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/*
|
||||
* Pipe SOCKS IRC connections through I2PTunnelIRCClient filtering,
|
||||
* to get the best of both worlds:
|
||||
*
|
||||
* - SOCKS lets you specify the host so you don't have to set up
|
||||
* a tunnel for each IRC server in advance
|
||||
* - IRC filtering for security
|
||||
*
|
||||
* @since 0.7.12
|
||||
* @author zzz
|
||||
*/
|
||||
public class I2PSOCKSIRCTunnel extends I2PSOCKSTunnel {
|
||||
|
||||
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(I2PSOCKSIRCTunnel.class);
|
||||
private static final int __clientId = 0;
|
||||
|
||||
public I2PSOCKSIRCTunnel(int localPort, Logging l, boolean ownDest, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super(localPort, l, ownDest, notifyThis, tunnel);
|
||||
setName(getLocalPort() + " -> 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -250,7 +250,8 @@
|
||||
}
|
||||
%></div>
|
||||
|
||||
<% if (!"sockstunnel".equals(indexBean.getInternalType(curClient))) { %>
|
||||
<% if (!("sockstunnel".equals(indexBean.getInternalType(curClient)) ||
|
||||
"socksirctunnel".equals(indexBean.getInternalType(curClient)))) { %>
|
||||
<div class="destinationField rowItem">
|
||||
<label>
|
||||
<% if ("httpclient".equals(indexBean.getInternalType(curClient)) || "connectclient".equals(indexBean.getInternalType(curClient))) { %>
|
||||
@ -288,6 +289,7 @@
|
||||
<option value="httpclient">HTTP</option>
|
||||
<option value="ircclient">IRC</option>
|
||||
<option value="sockstunnel">SOCKS 4/4a/5</option>
|
||||
<option value="socksirctunnel">SOCKS IRC</option>
|
||||
<option value="connectclient">CONNECT</option>
|
||||
<option value="streamrclient">Streamr</option>
|
||||
</select>
|
||||
|
12
history.txt
12
history.txt
@ -1,3 +1,15 @@
|
||||
2010-03-05 zzz
|
||||
* I2PSOCKSIRCTunnel:
|
||||
- New, for filtering IRC client traffic when using SOCKS
|
||||
* I2PTunnelIRCClient:
|
||||
- Make filter classes static and public for use by SOCKS
|
||||
- Eliminate redundant case conversion
|
||||
- Pass ISON message through (jIRCii uses it for pings)
|
||||
- Switch back to StringBuffer since it's used by 2 threads
|
||||
- Set daemon on filter threads
|
||||
* SOCKS5Server:
|
||||
- Fix handling of multiple authentication methods
|
||||
|
||||
2010-03-02 zzz
|
||||
* Console:
|
||||
- Add link to jobs.jsp on configservice.jsp
|
||||
|
@ -18,7 +18,7 @@ public class RouterVersion {
|
||||
/** deprecated */
|
||||
public final static String ID = "Monotone";
|
||||
public final static String VERSION = CoreVersion.VERSION;
|
||||
public final static long BUILD = 8;
|
||||
public final static long BUILD = 9;
|
||||
|
||||
/** for example "-test" */
|
||||
public final static String EXTRA = "";
|
||||
|
Reference in New Issue
Block a user