/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.vfs2.provider.sftp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

import org.apache.commons.vfs2.FileSystemOptions;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.Proxy;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SocketFactory;

Stream based proxy for JSch.

Use a command on the proxy that will forward the SSH stream to the target host and port.

Since:2.1
/** * Stream based proxy for JSch. * * <p> * Use a command on the proxy that will forward the SSH stream to the target host and port. * </p> * * @since 2.1 */
public class SftpStreamProxy implements Proxy {
Command format using bash built-in TCP stream.
/** * Command format using bash built-in TCP stream. */
public static final String BASH_TCP_COMMAND = "/bin/bash -c 'exec 3<>/dev/tcp/%s/%d; cat <&3 & cat >&3; kill $!";
Command format using netcat command.
/** * Command format using netcat command. */
public static final String NETCAT_COMMAND = "nc -q 0 %s %d"; private ChannelExec channel;
Command pattern to execute on the proxy host.

When run, the command output should be forwarded to the target host and port, and its input should be forwarded from the target host and port.

The command will be created for each host/port pair by using String.format(String, Object...) with two objects: the target host name (String) and the target port (Integer).

Here are two examples (that can be easily used by using the static members of this class):

  • nc -q 0 %s %d to use the netcat command (NETCAT_COMMAND)
  • /bin/bash -c 'exec 3<>/dev/tcp/%s/%d; cat <&3 & cat >&3; kill $! will use bash built-in TCP stream, which can be useful when there is no netcat available. (BASH_TCP_COMMAND)
/** * Command pattern to execute on the proxy host. * <p> * When run, the command output should be forwarded to the target host and port, and its input should be forwarded * from the target host and port. * </p> * <p> * The command will be created for each host/port pair by using {@linkplain String#format(String, Object...)} with * two objects: the target host name ({@linkplain String}) and the target port ({@linkplain Integer}). * </p> * <p> * <p> * Here are two examples (that can be easily used by using the static members of this class): * </p> * <ul> * <li><code>nc -q 0 %s %d</code> to use the netcat command ({@linkplain #NETCAT_COMMAND})</li> * <li><code>/bin/bash -c 'exec 3<>/dev/tcp/%s/%d; cat <&3 & cat >&3; kill $!</code> will use bash built-in TCP * stream, which can be useful when there is no netcat available. ({@linkplain #BASH_TCP_COMMAND})</li> * </ul> */
private final String commandFormat;
Hostname used to connect to the proxy host.
/** * Hostname used to connect to the proxy host. */
private final String proxyHost;
The options for connection.
/** * The options for connection. */
private final FileSystemOptions proxyOptions;
The password to be used for connection.
/** * The password to be used for connection. */
private final String proxyPassword;
Port used to connect to the proxy host.
/** * Port used to connect to the proxy host. */
private final int proxyPort;
Username used to connect to the proxy host.
/** * Username used to connect to the proxy host. */
private final String proxyUser; private Session session;
Creates a stream proxy.
Params:
  • commandFormat – A format string that will be used to create the command to execute on the proxy host using String.format(String, Object...). Two parameters are given to the format command, the target host name (String) and port (Integer).
  • proxyUser – The proxy user
  • proxyPassword – The proxy password
  • proxyHost – The proxy host
  • proxyPort – The port to connect to on the proxy
  • proxyOptions – Options used when connecting to the proxy
/** * Creates a stream proxy. * * @param commandFormat A format string that will be used to create the command to execute on the proxy host using * {@linkplain String#format(String, Object...)}. Two parameters are given to the format command, the * target host name (String) and port (Integer). * * @param proxyUser The proxy user * @param proxyPassword The proxy password * @param proxyHost The proxy host * @param proxyPort The port to connect to on the proxy * @param proxyOptions Options used when connecting to the proxy */
public SftpStreamProxy(final String commandFormat, final String proxyUser, final String proxyHost, final int proxyPort, final String proxyPassword, final FileSystemOptions proxyOptions) { this.proxyHost = proxyHost; this.proxyPort = proxyPort; this.proxyUser = proxyUser; this.proxyPassword = proxyPassword; this.commandFormat = commandFormat; this.proxyOptions = proxyOptions; } @Override public void close() { if (channel != null) { channel.disconnect(); } if (session != null) { session.disconnect(); } } @Override public void connect(final SocketFactory socketFactory, final String targetHost, final int targetPort, final int timeout) throws Exception { session = SftpClientFactory.createConnection(proxyHost, proxyPort, proxyUser.toCharArray(), proxyPassword.toCharArray(), proxyOptions); channel = (ChannelExec) session.openChannel("exec"); channel.setCommand(String.format(commandFormat, targetHost, targetPort)); channel.connect(timeout); } @Override public InputStream getInputStream() { try { return channel.getInputStream(); } catch (final IOException e) { throw new IllegalStateException("IOException getting the SSH proxy input stream", e); } } @Override public OutputStream getOutputStream() { try { return channel.getOutputStream(); } catch (final IOException e) { throw new IllegalStateException("IOException getting the SSH proxy output stream", e); } } @Override public Socket getSocket() { return null; } }