aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/sourceforge/jsocks/SocksSocket.java
blob: cf9ff65eb8265ed852482cf69adcb58791f267f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
package net.sourceforge.jsocks;

import java.net.*;
import java.io.*;

/**
 * SocksSocket tryies to look very similar to normal Socket,
 * while allowing connections through the SOCKS4 or 5 proxy.
 * To use this class you will have to identify proxy you need
 * to use, Proxy class allows you to set default proxy, which
 * will be used by all Socks aware sockets. You can also create
 * either Socks4Proxy or Socks5Proxy, and use them by passing to the 
 * appropriate constructors.
 * <P>
 * Using Socks package can be as easy as that:
 *
 * <pre><tt>
 *
 *     import Socks.*;
 *     ....
 *
 *     try{
 *        //Specify SOCKS5 proxy
 *        Proxy.setDefaultProxy("socks-proxy",1080);
 *
 *        //OR you still use SOCKS4
 *        //Code below uses SOCKS4 proxy
 *        //Proxy.setDefaultProxy("socks-proxy",1080,userName);
 *
 *        Socket s = SocksSocket("some.host.of.mine",13);
 *        readTimeFromSock(s);
 *     }catch(SocksException sock_ex){
 *        //Usually it will turn in more or less meaningfull message
 *        System.err.println("SocksException:"+sock_ex);
 *     }
 *
 * </tt></pre>
 *<P>
 * However if the need exist for more control, like resolving addresses
 * remotely, or using some non-trivial authentication schemes, it can be done.
 */

public class SocksSocket extends Socket{
   //Data members
   protected Proxy proxy;
   protected String localHost, remoteHost;
   protected InetAddress localIP, remoteIP;
   protected int localPort,remotePort;

   private Socket directSock = null;

   /**
    * Tryies to connect to given host and port
    * using default proxy. If no default proxy speciefied
    * it throws SocksException with error code SOCKS_NO_PROXY.
      @param host Machine to connect to.
      @param port Port to which to connect.
    * @see SocksSocket#SocksSocket(Proxy,String,int)
    * @see Socks5Proxy#resolveAddrLocally
    */
   public SocksSocket(String host,int port)
	  throws SocksException,UnknownHostException{
      this(Proxy.defaultProxy,host,port);
   }
   /**
    * Connects to host port using given proxy server.
      @param p Proxy to use.
      @param host Machine to connect to.
      @param port Port to which to connect.
      @throws UnknownHostException 
      If one of the following happens:
      <ol>

      <li> Proxy settings say that address should be resolved locally, but
           this fails.
      <li> Proxy settings say that the host should be contacted directly but
           host name can't be resolved. 
      </ol>
      @throws SocksException
      If one of the following happens:
      <ul>
       <li> Proxy is is null.
       <li> Proxy settings say that the host should be contacted directly but
            this fails.
       <li> Socks Server can't be contacted.
       <li> Authentication fails.
       <li> Connection is not allowed by the SOCKS proxy.
       <li> SOCKS proxy can't establish the connection.
       <li> Any IO error occured.
       <li> Any protocol error occured.
      </ul>
      @throws IOexception if anything is wrong with I/O.
      @see Socks5Proxy#resolveAddrLocally
    */
    public SocksSocket(Proxy p, String host, int port) throws SocksException,
			UnknownHostException {
		remoteHost = host;
		remotePort = port;
		remoteIP = InetAddress.getByName(host);
		doDirect();
	}

   /**
      Connects to given ip and port using given Proxy server.
      @param p Proxy to use.
      @param ip Machine to connect to.
      @param port Port to which to connect.

    */
   public SocksSocket(InetAddress ip, int port) throws SocksException{
      this.remoteIP = ip;
      this.remotePort = port;
      this.remoteHost = ip.getHostName();
      doDirect();
   }


   /**
    * These 2 constructors are used by the SocksServerSocket.
    * This socket simply overrides remoteHost, remotePort
    */
   protected SocksSocket(String  host,int port,Proxy proxy){
      this.remotePort = port;
      this.proxy = proxy;
      this.localIP = proxy.proxySocket.getLocalAddress();
      this.localPort = proxy.proxySocket.getLocalPort();
      this.remoteHost = host;
   }
   protected SocksSocket(InetAddress ip,int port,Proxy proxy){
      remoteIP = ip;
      remotePort = port;
      this.proxy = proxy;
      this.localIP = proxy.proxySocket.getLocalAddress();
      this.localPort = proxy.proxySocket.getLocalPort();
      remoteHost = remoteIP.getHostName();
   }

   /**
    * Same as Socket
    */
   public void close() throws IOException{
      if(proxy!= null)proxy.endSession();
      proxy = null;
   }
   /**
    * Same as Socket
    */
   public InputStream getInputStream(){
      return proxy.in;
   }
   /**
    * Same as Socket
    */
   public OutputStream getOutputStream(){
      return proxy.out;
   }
   /**
    * Same as Socket
    */
   public int getPort(){
      return remotePort;
   }
   /**
    * Returns remote host name, it is usefull in cases when addresses
    * are resolved by proxy, and we can't create InetAddress object.
      @return The name of the host this socket is connected to.
    */
   public String getHost(){
      return remoteHost;
   }
   /**
    * Get remote host as InetAddress object, might return null if 
    * addresses are resolved by proxy, and it is not possible to resolve
    * it locally
      @return Ip address of the host this socket is connected to, or null
      if address was returned by the proxy as DOMAINNAME and can't be
      resolved locally.
    */
   public InetAddress getInetAddress(){
      if(remoteIP == null){
	 try{
	   remoteIP = InetAddress.getByName(remoteHost);
	 }catch(UnknownHostException e){
	   return null;
	 }
      }
      return remoteIP;
   }

   /**
    * Get the port assigned by the proxy for the socket, not
    * the port on locall machine as in Socket. 
      @return Port of the socket used on the proxy server.
    */
   public int getLocalPort(){
      return localPort;
   }

   /**
    * Get address assigned by proxy to make a remote connection,
    * it might be different from the host specified for the proxy.
    * Can return null if socks server returned this address as hostname
    * and it can't be resolved locally, use getLocalHost() then.
      @return Address proxy is using to make a connection.
    */
   public InetAddress getLocalAddress(){
      if(localIP == null){
	 try{
	    localIP = InetAddress.getByName(localHost);
	 }catch(UnknownHostException e){
	   return null;
	 }
      }
      return localIP;
   }
   /**
      Get name of the host, proxy has assigned to make a remote connection
      for this socket. This method is usefull when proxy have returned
      address as hostname, and we can't resolve it on this machine.
      @return The name of the host proxy is using to make a connection.
   */
   public String getLocalHost(){
      return localHost;
   }

   /**
     Same as socket.
   */
   public void setSoLinger(boolean on,int val) throws SocketException{
      proxy.proxySocket.setSoLinger(on,val);
   }
   /**
     Same as socket.
   */
   public int getSoLinger(int timeout) throws SocketException{
      return proxy.proxySocket.getSoLinger();
   }
   /**
     Same as socket.
   */
   public void setSoTimeout(int timeout) throws SocketException{
      proxy.proxySocket.setSoTimeout(timeout);
   }
   /**
     Same as socket.
   */
   public int getSoTimeout(int timeout) throws SocketException{
      return proxy.proxySocket.getSoTimeout();
   }
   /**
     Same as socket.
   */
   public void setTcpNoDelay(boolean on) throws SocketException{
     proxy.proxySocket.setTcpNoDelay(on);
   }
   /**
     Same as socket.
   */
   public boolean getTcpNoDelay() throws SocketException{
     return proxy.proxySocket.getTcpNoDelay();
   }

   /**
     Get string representation of the socket.
   */
   public String toString(){
      if(directSock!=null) return "Direct connection:"+directSock;
      return ("Proxy:"+proxy+";"+"addr:"+remoteHost+",port:"+remotePort
                                +",localport:"+localPort);

   }

//Private Methods
//////////////////

   private void doDirect()throws SocksException{
      try{
         //System.out.println("IP:"+remoteIP+":"+remotePort);
         directSock = new Socket(remoteIP,remotePort);
         proxy.out = directSock.getOutputStream();
         proxy.in  = directSock.getInputStream();
         proxy.proxySocket = directSock;
         localIP = directSock.getLocalAddress();
         localPort = directSock.getLocalPort();
      }catch(IOException io_ex){
         throw new SocksException(Proxy.SOCKS_DIRECT_FAILED,
                                  "Direct connect failed:"+io_ex);
      }
   }

}