* I2PTunnel SOCKS and SOCKS IRC clients:
- Add SOCKS 5 outproxy support, with username/password authorization * I2PTunnel - Index page outproxy display cleanup
This commit is contained in:
@ -16,6 +16,7 @@ import net.i2p.client.I2PClientFactory;
|
||||
import net.i2p.client.I2PSession;
|
||||
import net.i2p.data.Base32;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.i2ptunnel.socks.I2PSOCKSTunnel;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SecureFileOutputStream;
|
||||
@ -226,6 +227,13 @@ public class TunnelController implements Logging {
|
||||
setListenOn();
|
||||
String listenPort = getListenPort();
|
||||
String sharedClient = getSharedClient();
|
||||
String proxyList = getProxyList();
|
||||
if (proxyList != null) {
|
||||
// set the outproxy property the socks tunnel wants
|
||||
Properties props = _tunnel.getClientOptions();
|
||||
if (!props.containsKey(I2PSOCKSTunnel.PROP_PROXY_DEFAULT))
|
||||
props.setProperty(I2PSOCKSTunnel.PROP_PROXY_DEFAULT, proxyList);
|
||||
}
|
||||
_tunnel.runSOCKSTunnel(new String[] { listenPort, sharedClient }, this);
|
||||
}
|
||||
|
||||
@ -234,6 +242,13 @@ public class TunnelController implements Logging {
|
||||
setListenOn();
|
||||
String listenPort = getListenPort();
|
||||
String sharedClient = getSharedClient();
|
||||
String proxyList = getProxyList();
|
||||
if (proxyList != null) {
|
||||
// set the outproxy property the socks tunnel wants
|
||||
Properties props = _tunnel.getClientOptions();
|
||||
if (!props.containsKey(I2PSOCKSTunnel.PROP_PROXY_DEFAULT))
|
||||
props.setProperty(I2PSOCKSTunnel.PROP_PROXY_DEFAULT, proxyList);
|
||||
}
|
||||
if (getPersistentClientKey()) {
|
||||
String privKeyFile = getPrivKeyFile();
|
||||
_tunnel.runSOCKSIRCTunnel(new String[] { listenPort, "false", privKeyFile }, this);
|
||||
|
@ -15,6 +15,7 @@ import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketOptions;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.i2ptunnel.I2PTunnel;
|
||||
import net.i2p.i2ptunnel.I2PTunnelClientBase;
|
||||
@ -61,15 +62,19 @@ public class I2PSOCKSTunnel extends I2PTunnelClientBase {
|
||||
}
|
||||
}
|
||||
|
||||
private static final String PROP_PROXY = "i2ptunnel.socks.proxy.";
|
||||
/** add "default" or port number */
|
||||
public static final String PROP_PROXY_PREFIX = "i2ptunnel.socks.proxy.";
|
||||
public static final String DEFAULT = "default";
|
||||
public static final String PROP_PROXY_DEFAULT = PROP_PROXY_PREFIX + DEFAULT;
|
||||
|
||||
private void parseOptions() {
|
||||
Properties opts = getTunnel().getClientOptions();
|
||||
proxies = new HashMap(0);
|
||||
proxies = new HashMap(1);
|
||||
for (Map.Entry e : opts.entrySet()) {
|
||||
String prop = (String)e.getKey();
|
||||
if ((!prop.startsWith(PROP_PROXY)) || prop.length() <= PROP_PROXY.length())
|
||||
if ((!prop.startsWith(PROP_PROXY_PREFIX)) || prop.length() <= PROP_PROXY_PREFIX.length())
|
||||
continue;
|
||||
String port = prop.substring(PROP_PROXY.length());
|
||||
String port = prop.substring(PROP_PROXY_PREFIX.length());
|
||||
List proxyList = new ArrayList(1);
|
||||
StringTokenizer tok = new StringTokenizer((String)e.getValue(), ", \t");
|
||||
while (tok.hasMoreTokens()) {
|
||||
@ -95,7 +100,22 @@ public class I2PSOCKSTunnel extends I2PTunnelClientBase {
|
||||
}
|
||||
|
||||
public List<String> getDefaultProxies() {
|
||||
return proxies.get("default");
|
||||
return proxies.get(DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Because getDefaultOptions() in super() is protected
|
||||
* @since 0.8.2
|
||||
*/
|
||||
public I2PSocketOptions buildOptions(Properties overrides) {
|
||||
Properties defaultOpts = getTunnel().getClientOptions();
|
||||
defaultOpts.putAll(overrides);
|
||||
// delayed start
|
||||
verifySocketManager();
|
||||
I2PSocketOptions opts = sockMgr.buildOptions(defaultOpts);
|
||||
if (!defaultOpts.containsKey(I2PSocketOptions.PROP_CONNECT_TIMEOUT))
|
||||
opts.setConnectTimeout(60 * 1000);
|
||||
return opts;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import java.util.Properties;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketOptions;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase;
|
||||
@ -83,7 +84,7 @@ public class SOCKS5Server extends SOCKSServer {
|
||||
if (manageRequest(in, out) == Command.UDP_ASSOCIATE)
|
||||
handleUDP(in, out);
|
||||
} catch (IOException e) {
|
||||
throw new SOCKSException("Connection error (" + e.getMessage() + ")");
|
||||
throw new SOCKSException("Connection error: " + e);
|
||||
}
|
||||
|
||||
setupCompleted = true;
|
||||
@ -94,12 +95,12 @@ public class SOCKS5Server extends SOCKSServer {
|
||||
* SOCKS "VER" field has been stripped from the input stream.
|
||||
*/
|
||||
private void init(DataInputStream in, DataOutputStream out) throws IOException, SOCKSException {
|
||||
int nMethods = in.readByte() & 0xff;
|
||||
int nMethods = in.readUnsignedByte();
|
||||
boolean methodOk = false;
|
||||
int method = Method.NO_ACCEPTABLE_METHODS;
|
||||
|
||||
for (int i = 0; i < nMethods; ++i) {
|
||||
int meth = in.readByte() & 0xff;
|
||||
int meth = in.readUnsignedByte();
|
||||
if (((!authRequired) && meth == Method.NO_AUTH_REQUIRED) ||
|
||||
(authRequired && meth == Method.USERNAME_PASSWORD)) {
|
||||
// That's fine, we do support this method
|
||||
@ -129,15 +130,15 @@ public class SOCKS5Server extends SOCKSServer {
|
||||
* @since 0.8.2
|
||||
*/
|
||||
private void verifyPassword(DataInputStream in, DataOutputStream out) throws IOException, SOCKSException {
|
||||
int c = in.readByte() & 0xff;
|
||||
int c = in.readUnsignedByte();
|
||||
if (c != AUTH_VERSION)
|
||||
throw new SOCKSException("Unsupported authentication version");
|
||||
c = in.readByte() & 0xff;
|
||||
c = in.readUnsignedByte();
|
||||
if (c <= 0)
|
||||
throw new SOCKSException("Bad authentication");
|
||||
byte[] user = new byte[c];
|
||||
in.readFully(user);
|
||||
c = in.readByte() & 0xff;
|
||||
c = in.readUnsignedByte();
|
||||
if (c <= 0)
|
||||
throw new SOCKSException("Bad authentication");
|
||||
byte[] pw = new byte[c];
|
||||
@ -165,13 +166,13 @@ public class SOCKS5Server extends SOCKSServer {
|
||||
* has been stripped out of the input/output streams.
|
||||
*/
|
||||
private int manageRequest(DataInputStream in, DataOutputStream out) throws IOException, SOCKSException {
|
||||
int socksVer = in.readByte() & 0xff;
|
||||
int socksVer = in.readUnsignedByte();
|
||||
if (socksVer != SOCKS_VERSION_5) {
|
||||
_log.debug("error in SOCKS5 request (protocol != 5? wtf?)");
|
||||
throw new SOCKSException("Invalid protocol version in request: " + socksVer);
|
||||
}
|
||||
|
||||
int command = in.readByte() & 0xff;
|
||||
int command = in.readUnsignedByte();
|
||||
switch (command) {
|
||||
case Command.CONNECT:
|
||||
break;
|
||||
@ -192,17 +193,15 @@ public class SOCKS5Server extends SOCKSServer {
|
||||
throw new SOCKSException("Invalid command in request");
|
||||
}
|
||||
|
||||
{
|
||||
// Reserved byte, should be 0x00
|
||||
byte rsv = in.readByte();
|
||||
}
|
||||
// Reserved byte, should be 0x00
|
||||
in.readByte();
|
||||
|
||||
int addressType = in.readByte() & 0xff;
|
||||
addressType = in.readUnsignedByte();
|
||||
switch (addressType) {
|
||||
case AddressType.IPV4:
|
||||
connHostName = new String("");
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
int octet = in.readByte() & 0xff;
|
||||
int octet = in.readUnsignedByte();
|
||||
connHostName += Integer.toString(octet);
|
||||
if (i != 3) {
|
||||
connHostName += ".";
|
||||
@ -213,7 +212,7 @@ public class SOCKS5Server extends SOCKSServer {
|
||||
break;
|
||||
case AddressType.DOMAINNAME:
|
||||
{
|
||||
int addrLen = in.readByte() & 0xff;
|
||||
int addrLen = in.readUnsignedByte();
|
||||
if (addrLen == 0) {
|
||||
_log.debug("0-sized address length? wtf?");
|
||||
throw new SOCKSException("Illegal DOMAINNAME length");
|
||||
@ -254,7 +253,7 @@ public class SOCKS5Server extends SOCKSServer {
|
||||
|
||||
sendRequestReply(Reply.SUCCEEDED, AddressType.IPV4, InetAddress.getByName("127.0.0.1"), null, 1, out);
|
||||
} catch (IOException e) {
|
||||
throw new SOCKSException("Connection error (" + e.getMessage() + ")");
|
||||
throw new SOCKSException("Connection error: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -347,7 +346,7 @@ public class SOCKS5Server extends SOCKSServer {
|
||||
try {
|
||||
out = new DataOutputStream(clientSock.getOutputStream());
|
||||
} catch (IOException e) {
|
||||
throw new SOCKSException("Connection error (" + e.getMessage() + ")");
|
||||
throw new SOCKSException("Connection error: " + e);
|
||||
}
|
||||
|
||||
// FIXME: here we should read our config file, select an
|
||||
@ -376,6 +375,7 @@ public class SOCKS5Server extends SOCKSServer {
|
||||
sendRequestReply(Reply.CONNECTION_NOT_ALLOWED_BY_RULESET, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
|
||||
} catch (IOException ioe) {}
|
||||
throw new SOCKSException(err);
|
||||
/****
|
||||
} else if (connPort == 80) {
|
||||
// rewrite GET line to include hostname??? or add Host: line???
|
||||
// or forward to local eepProxy (but that's a Socket not an I2PSocket)
|
||||
@ -386,6 +386,7 @@ public class SOCKS5Server extends SOCKSServer {
|
||||
sendRequestReply(Reply.CONNECTION_NOT_ALLOWED_BY_RULESET, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
|
||||
} catch (IOException ioe) {}
|
||||
throw new SOCKSException(err);
|
||||
****/
|
||||
} else {
|
||||
List<String> proxies = t.getProxies(connPort);
|
||||
if (proxies == null || proxies.isEmpty()) {
|
||||
@ -398,41 +399,182 @@ public class SOCKS5Server extends SOCKSServer {
|
||||
}
|
||||
int p = I2PAppContext.getGlobalContext().random().nextInt(proxies.size());
|
||||
String proxy = proxies.get(p);
|
||||
_log.debug("connecting to port " + connPort + " proxy " + proxy + " for " + connHostName + "...");
|
||||
// this isn't going to work, these need to be socks outproxies so we need
|
||||
// to do a socks session to them?
|
||||
destSock = t.createI2PSocket(I2PTunnel.destFromName(proxy));
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("connecting to proxy " + proxy + " for " + connHostName + " port " + connPort);
|
||||
|
||||
try {
|
||||
destSock = outproxyConnect(t, proxy);
|
||||
} catch (SOCKSException se) {
|
||||
try {
|
||||
sendRequestReply(Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
|
||||
} catch (IOException ioe) {}
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
confirmConnection();
|
||||
_log.debug("connection confirmed - exchanging data...");
|
||||
} catch (DataFormatException e) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("socks error", e);
|
||||
try {
|
||||
sendRequestReply(Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
|
||||
} catch (IOException ioe) {}
|
||||
throw new SOCKSException("Error in destination format");
|
||||
} catch (SocketException e) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("socks error", e);
|
||||
try {
|
||||
sendRequestReply(Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
|
||||
} catch (IOException ioe) {}
|
||||
throw new SOCKSException("Error connecting ("
|
||||
+ e.getMessage() + ")");
|
||||
throw new SOCKSException("Error connecting: " + e);
|
||||
} catch (IOException e) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("socks error", e);
|
||||
try {
|
||||
sendRequestReply(Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
|
||||
} catch (IOException ioe) {}
|
||||
throw new SOCKSException("Error connecting ("
|
||||
+ e.getMessage() + ")");
|
||||
throw new SOCKSException("Error connecting: " + e);
|
||||
} catch (I2PException e) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("socks error", e);
|
||||
try {
|
||||
sendRequestReply(Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
|
||||
} catch (IOException ioe) {}
|
||||
throw new SOCKSException("Error connecting ("
|
||||
+ e.getMessage() + ")");
|
||||
throw new SOCKSException("Error connecting: " + e);
|
||||
}
|
||||
|
||||
return destSock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Act as a SOCKS 5 client to connect to an outproxy
|
||||
* @return open socket or throws error
|
||||
* @since 0.8.2
|
||||
*/
|
||||
private I2PSocket outproxyConnect(I2PSOCKSTunnel tun, String proxy) throws IOException, SOCKSException, DataFormatException, I2PException {
|
||||
Properties overrides = new Properties();
|
||||
overrides.setProperty("option.i2p.streaming.connectDelay", "1000");
|
||||
I2PSocketOptions proxyOpts = tun.buildOptions(overrides);
|
||||
Destination dest = I2PTunnel.destFromName(proxy);
|
||||
if (dest == null)
|
||||
throw new SOCKSException("Outproxy not found");
|
||||
I2PSocket destSock = tun.createI2PSocket(I2PTunnel.destFromName(proxy), proxyOpts);
|
||||
try {
|
||||
DataOutputStream out = new DataOutputStream(destSock.getOutputStream());
|
||||
boolean authAvail = Boolean.valueOf(props.getProperty(I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH)).booleanValue();
|
||||
String configUser = null;
|
||||
String configPW = null;
|
||||
if (authAvail) {
|
||||
configUser = props.getProperty(I2PTunnelHTTPClientBase.PROP_OUTPROXY_USER_PREFIX + proxy);
|
||||
configPW = props.getProperty(I2PTunnelHTTPClientBase.PROP_OUTPROXY_PW_PREFIX + proxy);
|
||||
if (configUser == null || configPW == null) {
|
||||
configUser = props.getProperty(I2PTunnelHTTPClientBase.PROP_OUTPROXY_USER);
|
||||
configPW = props.getProperty(I2PTunnelHTTPClientBase.PROP_OUTPROXY_PW);
|
||||
if (configUser == null || configPW == null)
|
||||
authAvail = false;
|
||||
}
|
||||
}
|
||||
|
||||
// send the init
|
||||
out.writeByte(SOCKS_VERSION_5);
|
||||
if (authAvail) {
|
||||
out.writeByte(2);
|
||||
out.writeByte(Method.NO_AUTH_REQUIRED);
|
||||
out.writeByte(Method.USERNAME_PASSWORD);
|
||||
} else {
|
||||
out.writeByte(1);
|
||||
out.writeByte(Method.NO_AUTH_REQUIRED);
|
||||
}
|
||||
out.flush();
|
||||
|
||||
// read init reply
|
||||
DataInputStream in = new DataInputStream(destSock.getInputStream());
|
||||
// is this right or should we not try to do 5-to-4 conversion?
|
||||
int hisVersion = in.readByte();
|
||||
if (hisVersion != SOCKS_VERSION_5 /* && addrtype == AddressType.DOMAINNAME */ )
|
||||
throw new SOCKSException("SOCKS Outproxy is not Version 5");
|
||||
//else if (hisVersion != 4)
|
||||
// throw new SOCKSException("Unsupported SOCKS Outproxy Version");
|
||||
|
||||
int method = in.readByte();
|
||||
if (method == Method.NO_AUTH_REQUIRED) {
|
||||
// good
|
||||
} else if (method == Method.USERNAME_PASSWORD) {
|
||||
if (authAvail) {
|
||||
// send the auth
|
||||
out.writeByte(AUTH_VERSION);
|
||||
byte[] user = configUser.getBytes("UTF-8");
|
||||
byte[] pw = configPW.getBytes("UTF-8");
|
||||
out.writeByte(user.length);
|
||||
out.write(user);
|
||||
out.writeByte(pw.length);
|
||||
out.write(pw);
|
||||
out.flush();
|
||||
// read the auth reply
|
||||
if (in.readByte() != AUTH_VERSION)
|
||||
throw new SOCKSException("Bad auth version from outproxy");
|
||||
if (in.readByte() != AUTH_SUCCESS)
|
||||
throw new SOCKSException("Outproxy authorization failure");
|
||||
} else {
|
||||
throw new SOCKSException("Outproxy requires authorization, please configure username/password");
|
||||
}
|
||||
} else {
|
||||
throw new SOCKSException("Outproxy authorization failure");
|
||||
}
|
||||
|
||||
// send the connect command
|
||||
out.writeByte(SOCKS_VERSION_5);
|
||||
out.writeByte(Command.CONNECT);
|
||||
out.writeByte(0); // reserved
|
||||
out.writeByte(addressType);
|
||||
if (addressType == AddressType.IPV4) {
|
||||
out.write(InetAddress.getByName(connHostName).getAddress());
|
||||
} else if (addressType == AddressType.DOMAINNAME) {
|
||||
byte[] d = connHostName.getBytes("ISO-8859-1");
|
||||
out.writeByte(d.length);
|
||||
out.write(d);
|
||||
} else {
|
||||
// shouldn't happen
|
||||
throw new SOCKSException("Unknown address type for outproxy?");
|
||||
}
|
||||
out.writeShort(connPort);
|
||||
out.flush();
|
||||
|
||||
// read the connect reply
|
||||
hisVersion = in.readByte();
|
||||
if (hisVersion != SOCKS_VERSION_5)
|
||||
throw new SOCKSException("Outproxy response is not Version 5");
|
||||
int reply = in.readByte();
|
||||
in.readByte(); // reserved
|
||||
int type = in.readByte();
|
||||
int count = 0;
|
||||
if (type == AddressType.IPV4) {
|
||||
count = 4;
|
||||
} else if (type == AddressType.DOMAINNAME) {
|
||||
count = in.readUnsignedByte();
|
||||
} else if (type == AddressType.IPV6) {
|
||||
count = 16;
|
||||
} else {
|
||||
throw new SOCKSException("Unsupported address type in outproxy response");
|
||||
}
|
||||
byte[] addr = new byte[count];
|
||||
in.readFully(addr); // address
|
||||
in.readUnsignedShort(); // port
|
||||
if (reply != Reply.SUCCEEDED)
|
||||
throw new SOCKSException("Outproxy rejected request, response = " + reply);
|
||||
// throw away the address in the response
|
||||
// todo pass the response through?
|
||||
} catch (IOException e) {
|
||||
try { destSock.close(); } catch (IOException ioe) {}
|
||||
throw e;
|
||||
} catch (SOCKSException e) {
|
||||
try { destSock.close(); } catch (IOException ioe) {}
|
||||
throw e;
|
||||
}
|
||||
// that's it, caller will send confirmation to our client
|
||||
return destSock;
|
||||
}
|
||||
|
||||
// This isn't really the right place for this, we can't stop the tunnel once it starts.
|
||||
static SOCKSUDPTunnel _tunnel;
|
||||
static final Object _startLock = new Object();
|
||||
|
@ -20,8 +20,9 @@ public abstract class SOCKSServer {
|
||||
private static final Log _log = new Log(SOCKSServer.class);
|
||||
|
||||
/* Details about the connection requested by client */
|
||||
protected String connHostName = null;
|
||||
protected int connPort = 0;
|
||||
protected String connHostName;
|
||||
protected int connPort;
|
||||
protected int addressType;
|
||||
|
||||
/**
|
||||
* Perform server initialization (expecially regarding protected
|
||||
|
@ -862,16 +862,15 @@ public class IndexBean {
|
||||
}
|
||||
|
||||
// generic proxy stuff
|
||||
if ("httpclient".equals(_type) || "connectclient".equals(_type) || "httpbidirserver".equals(_type) ||
|
||||
if ("httpclient".equals(_type) || "connectclient".equals(_type) ||
|
||||
"sockstunnel".equals(_type) ||"socksirctunnel".equals(_type)) {
|
||||
for (String p : _booleanProxyOpts)
|
||||
config.setProperty("option." + p, "" + _booleanOptions.contains(p));
|
||||
}
|
||||
|
||||
if ("httpclient".equals(_type) || "connectclient".equals(_type)) {
|
||||
if (_proxyList != null)
|
||||
config.setProperty("proxyList", _proxyList);
|
||||
} else if ("ircclient".equals(_type) || "client".equals(_type) || "streamrclient".equals(_type)) {
|
||||
}
|
||||
|
||||
if ("ircclient".equals(_type) || "client".equals(_type) || "streamrclient".equals(_type)) {
|
||||
if (_targetDestination != null)
|
||||
config.setProperty("targetDestination", _targetDestination);
|
||||
} else if ("httpserver".equals(_type) || "httpbidirserver".equals(_type)) {
|
||||
|
@ -139,7 +139,7 @@
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<% if ("httpclient".equals(tunnelType) || "connectclient".equals(tunnelType)) {
|
||||
<% if ("httpclient".equals(tunnelType) || "connectclient".equals(tunnelType) || "sockstunnel".equals(tunnelType) || "socksirctunnel".equals(tunnelType)) {
|
||||
%><div id="destinationField" class="rowItem">
|
||||
<label for="proxyList" accesskey="x">
|
||||
<%=intl._("Outproxies")%>(<span class="accessKey">x</span>):
|
||||
|
@ -250,19 +250,24 @@
|
||||
}
|
||||
%></div>
|
||||
|
||||
<% 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))) { %>
|
||||
<% if ("httpclient".equals(indexBean.getInternalType(curClient)) || "connectclient".equals(indexBean.getInternalType(curClient)) ||
|
||||
"sockstunnel".equals(indexBean.getInternalType(curClient)) || "socksirctunnel".equals(indexBean.getInternalType(curClient))) { %>
|
||||
<%=intl._("Outproxy")%>:
|
||||
<% } else { %>
|
||||
<%=intl._("Destination")%>:
|
||||
<% } %>
|
||||
</label>
|
||||
<input class="freetext" size="40" readonly="readonly" value="<%=indexBean.getClientDestination(curClient)%>" />
|
||||
<div class="text">
|
||||
<% String cdest = indexBean.getClientDestination(curClient);
|
||||
if (cdest.length() > 0) {
|
||||
%><%=cdest%><%
|
||||
} else {
|
||||
%><i><%=intl._("none")%></i><%
|
||||
} %>
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<div class="descriptionField rowItem">
|
||||
<label><%=intl._("Description")%>:</label>
|
||||
|
Reference in New Issue
Block a user