1 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
3 Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in
13 the documentation and/or other materials provided with the distribution.
15 3. The names of the authors may not be used to endorse or promote products
16 derived from this software without specific prior written permission.
18 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
19 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
21 INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
22 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 package com.jcraft.jsch;
35 public class ChannelForwardedTCPIP extends Channel{
37 static java.util.Vector pool=new java.util.Vector();
39 static private final int LOCAL_WINDOW_SIZE_MAX=0x20000;
40 //static private final int LOCAL_WINDOW_SIZE_MAX=0x100000;
41 static private final int LOCAL_MAXIMUM_PACKET_SIZE=0x4000;
43 static private final int TIMEOUT=10*1000;
45 SocketFactory factory=null;
46 private Socket socket=null;
47 private ForwardedTCPIPDaemon daemon=null;
52 ChannelForwardedTCPIP(){
54 setLocalWindowSizeMax(LOCAL_WINDOW_SIZE_MAX);
55 setLocalWindowSize(LOCAL_WINDOW_SIZE_MAX);
56 setLocalPacketSize(LOCAL_MAXIMUM_PACKET_SIZE);
64 Class c=Class.forName(target);
65 daemon=(ForwardedTCPIPDaemon)c.newInstance();
67 PipedOutputStream out=new PipedOutputStream();
68 io.setInputStream(new PassiveInputStream(out
72 daemon.setChannel(this, getInputStream(), out);
73 Object[] foo=getPort(getSession(), rport);
74 daemon.setArg((Object[])foo[3]);
76 new Thread(daemon).start();
79 socket=(factory==null) ?
80 Util.createSocket(target, lport, TIMEOUT) :
81 factory.createSocket(target, lport);
82 socket.setTcpNoDelay(true);
83 io.setInputStream(socket.getInputStream());
84 io.setOutputStream(socket.getOutputStream());
86 sendOpenConfirmation();
89 sendOpenFailure(SSH_OPEN_ADMINISTRATIVELY_PROHIBITED);
95 thread=Thread.currentThread();
96 Buffer buf=new Buffer(rmpsize);
97 Packet packet=new Packet(buf);
100 while(thread!=null &&
103 i=io.in.read(buf.buffer,
106 -32 -20 // padding and mac
114 buf.putByte((byte)Session.SSH_MSG_CHANNEL_DATA);
115 buf.putInt(recipient);
118 getSession().write(packet, this, i);
122 //System.err.println(e);
129 void getData(Buffer buf){
130 setRecipient(buf.getInt());
131 setRemoteWindowSize(buf.getUInt());
132 setRemotePacketSize(buf.getInt());
133 byte[] addr=buf.getString();
134 int port=buf.getInt();
135 byte[] orgaddr=buf.getString();
136 int orgport=buf.getInt();
139 System.err.println("addr: "+Util.byte2str(addr));
140 System.err.println("port: "+port);
141 System.err.println("orgaddr: "+Util.byte2str(orgaddr));
142 System.err.println("orgport: "+orgport);
145 Session _session=null;
147 _session=getSession();
149 catch(JSchException e){
150 // session has been already down.
154 for(int i=0; i<pool.size(); i++){
155 Object[] foo=(Object[])(pool.elementAt(i));
156 if(foo[0]!=_session) continue;
157 if(((Integer)foo[1]).intValue()!=port) continue;
159 this.target=(String)foo[2];
160 if(foo[3]==null || (foo[3] instanceof Object[])){ this.lport=-1; }
161 else{ this.lport=((Integer)foo[3]).intValue(); }
163 this.factory=((SocketFactory)foo[5]);
168 //System.err.println("??");
173 static Object[] getPort(Session session, int rport){
175 for(int i=0; i<pool.size(); i++){
176 Object[] bar=(Object[])(pool.elementAt(i));
177 if(bar[0]!=session) continue;
178 if(((Integer)bar[1]).intValue()!=rport) continue;
185 static String[] getPortForwarding(Session session){
186 java.util.Vector foo=new java.util.Vector();
188 for(int i=0; i<pool.size(); i++){
189 Object[] bar=(Object[])(pool.elementAt(i));
190 if(bar[0]!=session) continue;
191 if(bar[3]==null){ foo.addElement(bar[1]+":"+bar[2]+":"); }
192 else{ foo.addElement(bar[1]+":"+bar[2]+":"+bar[3]); }
195 String[] bar=new String[foo.size()];
196 for(int i=0; i<foo.size(); i++){
197 bar[i]=(String)(foo.elementAt(i));
202 static String normalize(String address){
203 if(address==null){ return "localhost"; }
204 else if(address.length()==0 || address.equals("*")){ return ""; }
205 else{ return address; }
208 static void addPort(Session session, String _address_to_bind, int port, String target, int lport, SocketFactory factory) throws JSchException{
209 String address_to_bind=normalize(_address_to_bind);
211 if(getPort(session, port)!=null){
212 throw new JSchException("PortForwardingR: remote port "+port+" is already registered.");
214 Object[] foo=new Object[6];
215 foo[0]=session; foo[1]=new Integer(port);
216 foo[2]=target; foo[3]=new Integer(lport);
217 foo[4]=address_to_bind;
219 pool.addElement(foo);
222 static void addPort(Session session, String _address_to_bind, int port, String daemon, Object[] arg) throws JSchException{
223 String address_to_bind=normalize(_address_to_bind);
225 if(getPort(session, port)!=null){
226 throw new JSchException("PortForwardingR: remote port "+port+" is already registered.");
228 Object[] foo=new Object[5];
229 foo[0]=session; foo[1]=new Integer(port);
230 foo[2]=daemon; foo[3]=arg;
231 foo[4]=address_to_bind;
232 pool.addElement(foo);
235 static void delPort(ChannelForwardedTCPIP c){
236 Session _session=null;
238 _session=c.getSession();
240 catch(JSchException e){
241 // session has been already down.
244 delPort(_session, c.rport);
246 static void delPort(Session session, int rport){
247 delPort(session, null, rport);
249 static void delPort(Session session, String address_to_bind, int rport){
252 for(int i=0; i<pool.size(); i++){
253 Object[] bar=(Object[])(pool.elementAt(i));
254 if(bar[0]!=session) continue;
255 if(((Integer)bar[1]).intValue()!=rport) continue;
260 pool.removeElement(foo);
261 if(address_to_bind==null){
262 address_to_bind=(String)foo[4];
264 if(address_to_bind==null){
265 address_to_bind="0.0.0.0";
269 Buffer buf=new Buffer(100); // ??
270 Packet packet=new Packet(buf);
273 // byte SSH_MSG_GLOBAL_REQUEST 80
274 // string "cancel-tcpip-forward"
275 // boolean want_reply
276 // string address_to_bind (e.g. "127.0.0.1")
277 // uint32 port number to bind
279 buf.putByte((byte) 80/*SSH_MSG_GLOBAL_REQUEST*/);
280 buf.putString(Util.str2byte("cancel-tcpip-forward"));
281 buf.putByte((byte)0);
282 buf.putString(Util.str2byte(address_to_bind));
284 session.write(packet);
287 // throw new JSchException(e.toString());
290 static void delPort(Session session){
294 rport=new int[pool.size()];
295 for(int i=0; i<pool.size(); i++){
296 Object[] bar=(Object[])(pool.elementAt(i));
297 if(bar[0]==session) {
298 rport[count++]=((Integer)bar[1]).intValue();
302 for(int i=0; i<count; i++){
303 delPort(session, rport[i]);
307 public int getRemotePort(){return rport;}
308 void setSocketFactory(SocketFactory factory){
309 this.factory=factory;