comparison src/net/sourceforge/jsocks/Socks5Proxy.java @ 0:0ce5cc452d02

initial version
author Carl Byington <carl@five-ten-sg.com>
date Thu, 22 May 2014 10:41:19 -0700
parents
children 205ee2873330
comparison
equal deleted inserted replaced
-1:000000000000 0:0ce5cc452d02
1 package net.sourceforge.jsocks;
2 import java.io.IOException;
3 import java.io.InputStream;
4 import java.io.OutputStream;
5 import java.net.InetAddress;
6 import java.net.Socket;
7 import java.net.SocketException;
8 import java.net.UnknownHostException;
9 import java.util.Enumeration;
10 import java.util.Hashtable;
11
12 /**
13 SOCKS5 Proxy.
14 */
15
16 public class Socks5Proxy extends Proxy implements Cloneable {
17
18 //Data members
19 private Hashtable<Integer, Authentication> authMethods = new Hashtable<Integer, Authentication>();
20 private int selectedMethod;
21
22 boolean resolveAddrLocally = true;
23 UDPEncapsulation udp_encapsulation = null;
24
25
26 //Public Constructors
27 //====================
28
29 /**
30 Creates SOCKS5 proxy.
31 @param proxyHost Host on which a Proxy server runs.
32 @param proxyPort Port on which a Proxy server listens for connections.
33 @throws UnknownHostException If proxyHost can't be resolved.
34 */
35 public Socks5Proxy(String proxyHost, int proxyPort)
36 throws UnknownHostException {
37 super(proxyHost, proxyPort);
38 version = 5;
39 setAuthenticationMethod(0, new AuthenticationNone());
40 }
41
42
43 /**
44 Creates SOCKS5 proxy.
45 @param proxyIP Host on which a Proxy server runs.
46 @param proxyPort Port on which a Proxy server listens for connections.
47 */
48 public Socks5Proxy(InetAddress proxyIP, int proxyPort) {
49 super(proxyIP, proxyPort);
50 version = 5;
51 setAuthenticationMethod(0, new AuthenticationNone());
52 }
53
54
55 //Public instance methods
56 //========================
57
58
59 /**
60 * Wether to resolve address locally or to let proxy do so.
61 <p>
62 SOCKS5 protocol allows to send host names rather then IPs in the
63 requests, this option controls wether the hostnames should be send
64 to the proxy server as names, or should they be resolved locally.
65 @param doResolve Wether to perform resolution locally.
66 @return Previous settings.
67 */
68 public boolean resolveAddrLocally(boolean doResolve) {
69 boolean old = resolveAddrLocally;
70 resolveAddrLocally = doResolve;
71 return old;
72 }
73 /**
74 Get current setting on how the addresses should be handled.
75 @return Current setting for address resolution.
76 @see Socks5Proxy#resolveAddrLocally(boolean doResolve)
77 */
78 public boolean resolveAddrLocally() {
79 return resolveAddrLocally;
80 }
81
82 /**
83 Adds another authentication method.
84 @param methodId Authentication method id, see rfc1928
85 @param method Implementation of Authentication
86 @see Authentication
87 */
88 public boolean setAuthenticationMethod(int methodId,
89 Authentication method) {
90 if (methodId < 0 || methodId > 255)
91 return false;
92
93 if (method == null) {
94 //Want to remove a particular method
95 return (authMethods.remove(Integer.valueOf(methodId)) != null);
96 }
97 else {//Add the method, or rewrite old one
98 authMethods.put(Integer.valueOf(methodId), method);
99 }
100
101 return true;
102 }
103
104 /**
105 Get authentication method, which corresponds to given method id
106 @param methodId Authentication method id.
107 @return Implementation for given method or null, if one was not set.
108 */
109 public Authentication getAuthenticationMethod(int methodId) {
110 Object method = authMethods.get(Integer.valueOf(methodId));
111
112 if (method == null) return null;
113
114 return (Authentication)method;
115 }
116
117 /**
118 Creates a clone of this Proxy.
119 */
120 @Override
121 @SuppressWarnings("unchecked")
122 public Object clone() {
123 Socks5Proxy newProxy = new Socks5Proxy(proxyIP, proxyPort);
124 newProxy.authMethods = (Hashtable<Integer, Authentication>) this.authMethods.clone();
125 newProxy.resolveAddrLocally = resolveAddrLocally;
126 newProxy.chainProxy = chainProxy;
127 return newProxy;
128 }
129
130 //Public Static(Class) Methods
131 //==============================
132
133
134 //Protected Methods
135 //=================
136
137 @Override
138 protected Proxy copy() {
139 Socks5Proxy copy = new Socks5Proxy(proxyIP, proxyPort);
140 copy.authMethods = this.authMethods; //same Hash, no copy
141 copy.chainProxy = this.chainProxy;
142 copy.resolveAddrLocally = this.resolveAddrLocally;
143 return copy;
144 }
145 /**
146 *
147 *
148 */
149 @Override
150 protected void startSession()throws SocksException {
151 super.startSession();
152 Authentication auth;
153 Socket ps = proxySocket; //The name is too long
154
155 try {
156 byte nMethods = (byte) authMethods.size(); //Number of methods
157 byte[] buf = new byte[2 + nMethods]; //2 is for VER,NMETHODS
158 buf[0] = (byte) version;
159 buf[1] = nMethods; //Number of methods
160 int i = 2;
161 Enumeration<Integer> ids = authMethods.keys();
162
163 while (ids.hasMoreElements())
164 buf[i++] = (byte)ids.nextElement().intValue();
165
166 out.write(buf);
167 out.flush();
168 int versionNumber = in.read();
169 selectedMethod = in.read();
170
171 if (versionNumber < 0 || selectedMethod < 0) {
172 //EOF condition was reached
173 endSession();
174 throw(new SocksException(SOCKS_PROXY_IO_ERROR,
175 "Connection to proxy lost."));
176 }
177
178 if (versionNumber < version) {
179 //What should we do??
180 }
181
182 if (selectedMethod == 0xFF) { //No method selected
183 ps.close();
184 throw(new SocksException(SOCKS_AUTH_NOT_SUPPORTED));
185 }
186
187 auth = getAuthenticationMethod(selectedMethod);
188
189 if (auth == null) {
190 //This shouldn't happen, unless method was removed by other
191 //thread, or the server stuffed up
192 throw(new SocksException(SOCKS_JUST_ERROR,
193 "Speciefied Authentication not found!"));
194 }
195
196 Object[] in_out = auth.doSocksAuthentication(selectedMethod, ps);
197
198 if (in_out == null) {
199 //Authentication failed by some reason
200 throw(new SocksException(SOCKS_AUTH_FAILURE));
201 }
202
203 //Most authentication methods are expected to return
204 //simply the input/output streams associated with
205 //the socket. However if the auth. method requires
206 //some kind of encryption/decryption being done on the
207 //connection it should provide classes to handle I/O.
208 in = (InputStream) in_out[0];
209 out = (OutputStream) in_out[1];
210
211 if (in_out.length > 2)
212 udp_encapsulation = (UDPEncapsulation) in_out[2];
213 }
214 catch (SocksException s_ex) {
215 throw s_ex;
216 }
217 catch (UnknownHostException uh_ex) {
218 throw(new SocksException(SOCKS_PROXY_NO_CONNECT));
219 }
220 catch (SocketException so_ex) {
221 throw(new SocksException(SOCKS_PROXY_NO_CONNECT));
222 }
223 catch (IOException io_ex) {
224 //System.err.println(io_ex);
225 throw(new SocksException(SOCKS_PROXY_IO_ERROR, "" + io_ex));
226 }
227 }
228
229 @Override
230 protected ProxyMessage formMessage(int cmd, InetAddress ip, int port) {
231 return new Socks5Message(cmd, ip, port);
232 }
233 @Override
234 protected ProxyMessage formMessage(int cmd, String host, int port)
235 throws UnknownHostException {
236 if (resolveAddrLocally)
237 return formMessage(cmd, InetAddress.getByName(host), port);
238 else
239 return new Socks5Message(cmd, host, port);
240 }
241 @Override
242 protected ProxyMessage formMessage(InputStream in)
243 throws SocksException,
244 IOException {
245 return new Socks5Message(in);
246 }
247
248 }