📄 abstractvpnclient.java
字号:
*
* @return ok
* @throws IOException
* @throws UnsupportedAuthenticationException
* @throws HttpException
*/
protected boolean retrievePersistantForwardingTunnels() throws IOException, HttpException, UnsupportedAuthenticationException,
AuthenticationCancelledException {
HttpClient client = getHttpClient();
GetMethod get = new GetMethod("/getTunnels.do");
get.setParameter("ticket", ticket);
HttpResponse response = client.execute(get);
try {
XMLElement xml = new XMLElement();
xml.parseFromReader(new InputStreamReader(response.getInputStream()));
if (xml.getName().equals("tunnels")) {
forwardingTunnels.removeAllElements();
// Create any tunnels that should be started upon registration
// #ifdef DEBUG
log.info("Looking for tunnels to open");
// #endif
for (Enumeration e2 = xml.enumerateChildren(); e2.hasMoreElements();) {
XMLElement el2 = (XMLElement) e2.nextElement();
if (el2.getName().equals("tunnel")) {
int id = el2.getIntAttribute("id");
int type = el2.getIntAttribute("type");
boolean autoStart = el2.getBooleanAttribute("autoStart", "true", "false", false);
String transport = (String) el2.getAttribute("transport");
String username = (String) el2.getAttribute("username");
int sourcePort = el2.getIntAttribute("sourcePort");
int destinationPort = el2.getIntAttribute("destinationPort");
String destinationHost = el2.getStringAttribute("destinationHost");
boolean allowExternalHosts = el2.getBooleanAttribute("allowExternalHosts", "true", "false", false);
// #ifdef DEBUG
log.info("Tunnel " + transport + " from " + sourcePort + " to " + destinationHost + ":" + destinationPort);
// #endif
forwardingTunnels.addElement(new DefaultTunnel(id, type, autoStart, transport, username, sourcePort,
destinationPort, destinationHost, allowExternalHosts, true, false, destinationHost + ":"
+ destinationPort, false));
} else {
// #ifdef DEBUG
log.error("Invalid child element in success.tunnels");
// #endif
}
}
return true;
} else {
// #ifdef DEBUG
log.error("Did not get a list of tunnels to start, got '" + xml.toString() + " instead.");
// #endif
return false;
}
} finally {
response.close();
}
}
/**
* Unregisters an application tunnel.
*
* @param tunnel
* @return
* @throws IOException
* @throws UnsupportedAuthenticationException
* @throws HttpException
*/
public boolean unregisterApplicationTunnel(Tunnel tunnel) throws IOException, HttpException,
UnsupportedAuthenticationException, AuthenticationCancelledException {
HttpClient client = getHttpClient();
GetMethod get = new GetMethod("/unregisterListeningSocket.do");
get.setParameter("ticket", ticket);
get.setParameter("tunnel", tunnel.getTicket());
HttpResponse response = client.execute(get);
try {
XMLElement xml = new XMLElement();
xml.parseFromReader(new InputStreamReader(response.getInputStream()));
return xml.getName().equalsIgnoreCase("success");
} finally {
response.close();
}
}
/**
* Called by a {@link VPNConnectionListener}to register a new forwarding
* tunnel.
*
* @param tunnel
*/
protected void registerForwardingTunnel(VPNTunnel tunnel) {
activeForwardingTunnels.addElement(tunnel);
}
/**
* Called by a {@link VPNConnectionListener}to unregister a new forwarding
* tunnel.
*
* @param tunnel
*/
protected void unregisterForwardingTunnel(VPNTunnel tunnel) {
activeForwardingTunnels.removeElement(tunnel);
}
/**
* Select a random port. NOTE: this method does not gaurentee that the port
* is available.
*
* @return
*/
protected int selectRandomPort() {
SecureRandom rnd = SecureRandom.getInstance();
int n = HIGHEST_RANDOM_PORT - LOWEST_RANDOM_PORT + 1;
int i = rnd.nextInt() % n;
if (i < 0)
i = -i;
return LOWEST_RANDOM_PORT + i;
}
/**
* Create a permanent listening socket.
*
* @param portToBind
* @param hostToConnect
* @param portToConnect
* @param allowExternalHosts
* @return
*/
public VPNConnectionListener createPermanentListeningSocket(Tunnel tunnel) {
try {
// #ifdef DEBUG
log.info("Attempting to create a listening socket for " + tunnel.getDestinationHost() + ":"
+ tunnel.getDestinationPort() + " on the port " + tunnel.getSourcePort());
// #endif
return startListeningSocket(tunnel);
} catch (IOException ex) {
// #ifdef DEBUG
log.info("Failed to start listening socket", ex);
// #endif
return null;
}
}
/**
* Attempt to create a tunnel that listens on the callers preferred port. If
* the port is already being used then generate a random port and return the
* listening port to the caller.
*
* @param hostToConnect host to connect
* @param portToConnect port to connect
* @param allowExternalHosts allow hosts other than the one the client is
* running on to connect
* @param preferredListeningPort the port on which to try and create a
* listener first. Upon failure a random port will be used
* @param maxAttempts the maximum number of times to try and create a
* listener
* @param temporarySingleConnect true if this tunnel can be used only once
* @return the listener
*/
public VPNConnectionListener createTemporaryListeningSocket(String hostToConnect, int portToConnect,
boolean allowExternalHosts, int preferredListeningPort,
int maxAttempts, boolean temporarySingleConnect) {
try {
if (preferredListeningPort == -1) {
throw new IOException();
}
// #ifdef DEBUG
log.info("Attempting to create a " + (temporarySingleConnect ? "temporary single connect" : "temporary")
+ " listening socket for " + hostToConnect + ":" + portToConnect + " on the preferred port "
+ preferredListeningPort);
// #endif
Tunnel tunnel = new DefaultTunnel(-1, Tunnel.LOCAL_TUNNEL, false, Tunnel.TCP_TUNNEL, username, preferredListeningPort,
portToConnect, hostToConnect, allowExternalHosts, false, temporarySingleConnect, hostToConnect + ":"
+ portToConnect, false);
return startListeningSocket(tunnel);
} catch (IOException ex) {
// #ifdef DEBUG
if (preferredListeningPort == -1) {
log.info("Preferred port disabled, choosing a random one.");
} else {
log.info("Preferred port failed as its probably in use by another application");
}
// #endif
/**
* The preferred port failed so lets try up to the maximum on a
* random port
*/
int port = -1;
for (int i = 0; i < maxAttempts; i++) {
try {
port = selectRandomPort();
// #ifdef DEBUG
log.info("Attempting to create a listening socket for " + hostToConnect + ":" + portToConnect
+ " on the random port " + port);
// #endif
Tunnel tunnel = new DefaultTunnel(-1, Tunnel.LOCAL_TUNNEL, false, Tunnel.TCP_TUNNEL, username, port,
portToConnect, hostToConnect, allowExternalHosts, false, temporarySingleConnect, hostToConnect
+ ":" + portToConnect, false);
return startListeningSocket(tunnel);
} catch (IOException ex2) {
// Ignore and try again up to maxAttempts
// #ifdef DEBUG
log.info("Random port " + port + " failed! " + (maxAttempts - i) + " attempts left", ex2);
// #endif
}
}
}
// #ifdef DEBUG
log.info("All attempts to create a listening socket failed");
// #endif
// If we reacahed here we failed so return a failure value
return null;
}
/**
* Start a listening socket, wait for connections and tunnel all connected
* sockets to a remote host.
*
* @param tunnel Tunnel
* @return VPNConnectionListener
* @throws IOException
*/
public VPNConnectionListener startListeningSocket(Tunnel tunnel) throws IOException {
VPNConnectionListener listener = new VPNConnectionListener(this, getTXIOListener(), getRXIOListener(), tunnel);
listener.start();
// Save the listener to our table
activeListeners.put(listener.getTicket(), listener);
return listener;
}
public MultiplexedConnection startRemoteForwarding(Tunnel tunnel) throws IOException {
if (tunnel.getType() != Tunnel.REMOTE_TUNNEL)
throw new IOException("Invalid tunnel type " + tunnel.getType()
+ ": only remote forwards can request a remote listening socket");
try {
XMLElement xml = registerListeningSocket(true, tunnel);
if (xml == null)
throw new IOException("Unexpected error in fowarding registration!");
String ticket = xml.getContent();
tunnel.setTicket(ticket);
HttpClient client = getHttpClient();
client.setCredentials(new PasswordCredentials(getTicket(), tunnel.getTicket()));
client.setPreemtiveAuthentication(true);
GetMethod listen = new GetMethod("CONNECT", (tunnel.isAllowExternalHosts() ? "0.0.0.0" : "127.0.0.1") + ":"
+ tunnel.getSourcePort() + "#" + tunnel.getDestinationHost() + ":" + tunnel.getDestinationPort());
HttpResponse response = client.execute(listen);
MultiplexedConnection con = new MultiplexedConnection(0, 0, 0, response.getConnection().getInputStream(), response
.getConnection().getOutputStream(), new ChannelFactory() {
public Channel createChannel(String type) {
Channel channel = new SocketChannel();
channel.addListener(AbstractVPNClient.this);
return channel;
}
});
remoteListeners.put(tunnel.getTicket(), con);
return con;
} catch (AuthenticationCancelledException ex) {
throw new IOException("Unexpected authentication error in HTTP request: " + ex.getMessage());
} catch (UnsupportedAuthenticationException ex) {
throw new IOException("Unexpected authentication error in HTTP request: " + ex.getMessage());
} catch (HttpException ex) {
throw new IOException("Unexpected HTTP error: " + ex.getMessage());
} catch (UnknownHostException ex) {
throw new IOException("Unexpected host not found error in HTTP request: " + ex.getMessage());
} catch (Exception ex) {
throw new IOException(ex.getMessage());
}
}
public boolean unregisterListeningSocket(Tunnel tunnel) {
try {
HttpClient client = getHttpClient();
GetMethod get = new GetMethod("/unregisterListeningSocket.do");
get.setParameter("ticket", getTicket());
get.setParameter("tunnel", tunnel.getTicket());
HttpResponse response = client.execute(get);
try {
XMLElement xml = new XMLElement();
xml.parseFromReader(new InputStreamReader(response.getInputStream()));
return xml.getName().equalsIgnoreCase("success");
} finally {
registeredListeningSockets.remove(tunnel.getTicket());
response.close();
}
} catch (MalformedURLException ex) {
// #ifdef DEBUG
log.info("Failed to construct url", ex);
// #endif
} catch (Throwable ex) {
// #ifdef DEBUG
log.info("Failed to connect url", ex);
// #endif
}
return false;
}
/**
* Register a tunnel with the server. An XML element will be return with id
* and ticket attributes. The id attribute is the tunnel ID. A new tunnel
* will be created and the new id returned if the supplied
* <code>Tunnel</code> object has an ID of -1.
*
* @param start automatically start the tunnel
* @param tunnel the tunnel
* @return tunnel details
*/
public XMLElement registerListeningSocket(boolean start, Tunnel tunnel) throws Exception {
HttpClient client = getHttpClient();
GetMethod get = new GetMethod("/registerListeningSocket.do");
get.setParameter("ticket", getTicket());
get.setParameter("start", String.valueOf(start));
if (tunnel.getId() == -1) {
get.setParameter("sourcePort", String.valueOf(tunnel.getSourcePort()));
get.setParameter("destinationHost", tunnel.getDestinationHost());
get.setParameter("destinationPort", String.valueOf(tunnel.getDestinationPort()));
get.setParameter("allowExternalHosts", String.valueOf(tunnel.isAllowExternalHosts()));
get.setParameter("permanent", String.valueOf(tunnel.isPermanent()));
get.setParameter("autoStart", String.valueOf(tunnel.isAutoStart()));
get.setParameter("transport", tunnel.getTransport());
get.setParameter("type", String.valueOf(tunnel.getType()));
} else {
get.setParameter("id", String.valueOf(tunnel.getId()));
}
HttpResponse response = client.execute(get);
try {
// #ifdef DEBUG
log.info("Registering tunnel");
// #endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -