349
|
1 package net.sourceforge.jsocks;
|
|
2 import java.net.InetAddress;
|
|
3 import java.net.UnknownHostException;
|
|
4 import java.util.*;
|
|
5
|
|
6 /**
|
|
7 * Class InetRange provides the means of defining the range of inetaddresses.
|
|
8 * It's used by Proxy class to store and look up addresses of machines, that
|
|
9 * should be contacted directly rather then through the proxy.
|
|
10 * <P>
|
|
11 * InetRange provides several methods to add either standalone addresses, or
|
|
12 * ranges (e.g. 100.200.300.0:100.200.300.255, which covers all addresses
|
|
13 * on on someones local network). It also provides methods for checking wether
|
|
14 * given address is in this range. Any number of ranges and standalone
|
|
15 * addresses can be added to the range.
|
|
16 */
|
|
17 public class InetRange implements Cloneable{
|
|
18
|
|
19 Hashtable host_names;
|
|
20 Vector all;
|
|
21 Vector end_names;
|
|
22
|
|
23 boolean useSeparateThread = true;
|
|
24
|
|
25 /**
|
|
26 * Creates the empty range.
|
|
27 */
|
|
28 public InetRange(){
|
|
29 all = new Vector();
|
|
30 host_names = new Hashtable();
|
|
31 end_names = new Vector();
|
|
32 }
|
|
33
|
|
34 /**
|
|
35 * Adds another host or range to this range.
|
|
36 The String can be one of those:
|
|
37 <UL>
|
|
38 <li> Host name. eg.(Athena.myhost.com or 45.54.56.65)
|
|
39
|
|
40 <li> Range in the form .myhost.net.au <BR>
|
|
41 In which case anything that ends with .myhost.net.au will
|
|
42 be considered in the range.
|
|
43
|
|
44 <li> Range in the form ddd.ddd.ddd. <BR>
|
|
45 This will be treated as range ddd.ddd.ddd.0 to ddd.ddd.ddd.255.
|
|
46 It is not necessary to specify 3 first bytes you can use just
|
|
47 one or two. For example 130. will cover address between 130.0.0.0
|
|
48 and 13.255.255.255.
|
|
49
|
|
50 <li> Range in the form host_from[: \t\n\r\f]host_to. <br>
|
|
51 That is two hostnames or ips separated by either whitespace
|
|
52 or colon.
|
|
53 </UL>
|
|
54 */
|
|
55 public synchronized boolean add(String s){
|
|
56 if(s == null) return false;
|
|
57
|
|
58 s = s.trim();
|
|
59 if(s.length() == 0) return false;
|
|
60
|
|
61 Object[] entry;
|
|
62
|
|
63 if(s.charAt(s.length()-1) == '.'){
|
|
64 //thing like: 111.222.33.
|
|
65 //it is being treated as range 111.222.33.000 - 111.222.33.255
|
|
66
|
|
67 int[] addr = ip2intarray(s);
|
|
68 long from,to;
|
|
69 from = to = 0;
|
|
70
|
|
71 if(addr == null) return false;
|
|
72 for(int i = 0; i< 4;++i){
|
|
73 if(addr[i]>=0)
|
|
74 from += (((long)addr[i]) << 8*(3-i));
|
|
75 else{
|
|
76 to = from;
|
|
77 while(i<4)
|
|
78 to += 255l << 8*(3-i++);
|
|
79 break;
|
|
80 }
|
|
81 }
|
|
82 entry = new Object[] {s,null,new Long(from),new Long(to)};
|
|
83 all.addElement(entry);
|
|
84
|
|
85 }else if(s.charAt(0) == '.'){
|
|
86 //Thing like: .myhost.com
|
|
87
|
|
88 end_names.addElement(s);
|
|
89 all.addElement(new Object[]{s,null,null,null});
|
|
90 }else{
|
|
91 StringTokenizer tokens = new StringTokenizer(s," \t\r\n\f:");
|
|
92 if(tokens.countTokens() > 1){
|
|
93 entry = new Object[] {s,null,null,null};
|
|
94 resolve(entry,tokens.nextToken(),tokens.nextToken());
|
|
95 all.addElement(entry);
|
|
96 }else{
|
|
97 entry = new Object[] {s,null,null,null};
|
|
98 all.addElement(entry);
|
|
99 host_names.put(s,entry);
|
|
100 resolve(entry);
|
|
101 }
|
|
102
|
|
103 }
|
|
104
|
|
105 return true;
|
|
106 }
|
|
107
|
|
108 /**
|
|
109 * Adds another ip for this range.
|
|
110 @param ip IP os the host which should be added to this range.
|
|
111 */
|
|
112 public synchronized void add(InetAddress ip){
|
|
113 long from, to;
|
|
114 from = to = ip2long(ip);
|
|
115 all.addElement(new Object[]{ip.getHostName(),ip,new Long(from),
|
|
116 new Long(to)});
|
|
117 }
|
|
118
|
|
119 /**
|
|
120 * Adds another range of ips for this range.Any host with ip address
|
|
121 greater than or equal to the address of from and smaller than or equal
|
|
122 to the address of to will be included in the range.
|
|
123 @param from IP from where range starts(including).
|
|
124 @param to IP where range ends(including).
|
|
125 */
|
|
126 public synchronized void add(InetAddress from,InetAddress to){
|
|
127 all.addElement(new Object[]{from.getHostAddress()+":"+to.getHostAddress()
|
|
128 ,null,new Long(ip2long(from)),
|
|
129 new Long(ip2long(to))});
|
|
130 }
|
|
131
|
|
132 /**
|
|
133 * Checks wether the givan host is in the range. Attempts to resolve
|
|
134 host name if required.
|
|
135 @param host Host name to check.
|
|
136 @return true If host is in the range, false otherwise.
|
|
137 * @see InetRange#contains(String,boolean)
|
|
138 */
|
|
139 public synchronized boolean contains(String host){
|
|
140 return contains(host,true);
|
|
141 }
|
|
142
|
|
143 /**
|
|
144 * Checks wether the given host is in the range.
|
|
145 * <P>
|
|
146 * Algorithm: <BR>
|
|
147 * <ol>
|
|
148 * <li>Look up if the hostname is in the range (in the Hashtable).
|
|
149 * <li>Check if it ends with one of the speciefied endings.
|
|
150 * <li>Check if it is ip(eg.130.220.35.98). If it is check if it is
|
|
151 * in the range.
|
|
152 * <li>If attemptResolve is true, host is name, rather than ip, and
|
|
153 * all previous attempts failed, try to resolve the hostname, and
|
|
154 * check wether the ip associated with the host is in the range.It
|
|
155 * also repeats all previos steps with the hostname obtained from
|
|
156 * InetAddress, but the name is not allways the full name,it is
|
|
157 * quite likely to be the same. Well it was on my machine.
|
|
158 * </ol>
|
|
159 @param host Host name to check.
|
|
160 @param attemptResolve Wether to lookup ip address which corresponds
|
|
161 to the host,if required.
|
|
162 @return true If host is in the range, false otherwise.
|
|
163 */
|
|
164 public synchronized boolean contains(String host,boolean attemptResolve){
|
|
165 if(all.size() ==0) return false; //Empty range
|
|
166
|
|
167 host = host.trim();
|
|
168 if(host.length() == 0) return false;
|
|
169
|
|
170 if(checkHost(host)) return true;
|
|
171 if(checkHostEnding(host)) return true;
|
|
172
|
|
173 long l = host2long(host);
|
|
174 if(l >=0) return contains(l);
|
|
175
|
|
176 if(!attemptResolve) return false;
|
|
177
|
|
178 try{
|
|
179 InetAddress ip = InetAddress.getByName(host);
|
|
180 return contains(ip);
|
|
181 }catch(UnknownHostException uhe){
|
|
182
|
|
183 }
|
|
184
|
|
185 return false;
|
|
186 }
|
|
187
|
|
188 /**
|
|
189 * Checks wether the given ip is in the range.
|
|
190 @param ip Address of the host to check.
|
|
191 @return true If host is in the range, false otherwise.
|
|
192 */
|
|
193 public synchronized boolean contains(InetAddress ip){
|
|
194 if(checkHostEnding(ip.getHostName())) return true;
|
|
195 if(checkHost(ip.getHostName())) return true;
|
|
196 return contains(ip2long(ip));
|
|
197 }
|
|
198 /**
|
|
199 Get all entries in the range as strings. <BR>
|
|
200 These strings can be used to delete entries from the range
|
|
201 with remove function.
|
|
202 @return Array of entries as strings.
|
|
203 @see InetRange#remove(String)
|
|
204 */
|
|
205 public synchronized String[] getAll(){
|
|
206 int size = all.size();
|
|
207 Object entry[];
|
|
208 String all_names[] = new String[size];
|
|
209
|
|
210 for(int i=0;i<size;++i){
|
|
211 entry = (Object[]) all.elementAt(i);
|
|
212 all_names[i] = (String) entry[0];
|
|
213 }
|
|
214 return all_names;
|
|
215 }
|
|
216 /**
|
|
217 Removes an entry from this range.<BR>
|
|
218 @param s Entry to remove.
|
|
219 @return true if successfull.
|
|
220 */
|
|
221 public synchronized boolean remove(String s){
|
|
222 Enumeration eEnum = all.elements();
|
|
223 while(eEnum.hasMoreElements()){
|
|
224 Object[] entry = (Object[]) eEnum.nextElement();
|
|
225 if(s.equals(entry[0])){
|
|
226 all.removeElement(entry);
|
|
227 end_names.removeElement(s);
|
|
228 host_names.remove(s);
|
|
229 return true;
|
|
230 }
|
|
231 }
|
|
232 return false;
|
|
233 }
|
|
234
|
|
235 /** Get string representaion of this Range.*/
|
|
236 public String toString(){
|
|
237 String all[] = getAll();
|
|
238 if(all.length == 0) return "";
|
|
239
|
|
240 String s = all[0];
|
|
241 for(int i=1;i<all.length;++i)
|
|
242 s += "; "+all[i];
|
|
243 return s;
|
|
244 }
|
|
245
|
|
246 /** Creates a clone of this Object*/
|
|
247 public Object clone(){
|
|
248 InetRange new_range = new InetRange();
|
|
249 new_range.all = (Vector)all.clone();
|
|
250 new_range.end_names = (Vector) end_names.clone();
|
|
251 new_range.host_names = (Hashtable)host_names.clone();
|
|
252 return new_range;
|
|
253 }
|
|
254
|
|
255
|
|
256 //Private methods
|
|
257 /////////////////
|
|
258 /**
|
|
259 * Same as previous but used internally, to avoid
|
|
260 * unnecessary convertion of IPs, when checking subranges
|
|
261 */
|
|
262 private synchronized boolean contains(long ip){
|
|
263 Enumeration eEnum = all.elements();
|
|
264 while(eEnum.hasMoreElements()){
|
|
265 Object[] obj = (Object[]) eEnum.nextElement();
|
|
266 Long from = obj[2]==null?null:(Long)obj[2];
|
|
267 Long to = obj[3]==null?null:(Long)obj[3];
|
|
268 if(from != null && from.longValue()<= ip
|
|
269 && to.longValue() >= ip) return true;
|
|
270
|
|
271 }
|
|
272 return false;
|
|
273 }
|
|
274
|
|
275 private boolean checkHost(String host){
|
|
276 return host_names.containsKey(host);
|
|
277 }
|
|
278 private boolean checkHostEnding(String host){
|
|
279 Enumeration eEnum = end_names.elements();
|
|
280 while(eEnum.hasMoreElements()){
|
|
281 if(host.endsWith((String) eEnum.nextElement())) return true;
|
|
282 }
|
|
283 return false;
|
|
284 }
|
|
285 private void resolve(Object[] entry){
|
|
286 //First check if it's in the form ddd.ddd.ddd.ddd.
|
|
287 long ip = host2long((String) entry[0]);
|
|
288 if(ip >= 0){
|
|
289 entry[2] = entry[3] = new Long(ip);
|
|
290 }else{
|
|
291 InetRangeResolver res = new InetRangeResolver(entry);
|
|
292 res.resolve(useSeparateThread);
|
|
293 }
|
|
294 }
|
|
295 private void resolve(Object[] entry,String from,String to){
|
|
296 long f,t;
|
|
297 if((f=host2long(from))>= 0 && (t=host2long(to)) >= 0){
|
|
298 entry[2] = new Long(f);
|
|
299 entry[3] = new Long(t);
|
|
300 }else{
|
|
301 InetRangeResolver res = new InetRangeResolver(entry,from,to);
|
|
302 res.resolve(useSeparateThread);
|
|
303 }
|
|
304 }
|
|
305
|
|
306
|
|
307
|
|
308 //Class methods
|
|
309 ///////////////
|
|
310
|
|
311 //Converts ipv4 to long value(unsigned int)
|
|
312 ///////////////////////////////////////////
|
|
313 static long ip2long(InetAddress ip){
|
|
314 long l=0;
|
|
315 byte[] addr = ip.getAddress();
|
|
316
|
|
317 if(addr.length ==4){ //IPV4
|
|
318 for(int i=0;i<4;++i)
|
|
319 l += (((long)addr[i] &0xFF) << 8*(3-i));
|
|
320 }else{ //IPV6
|
|
321 return 0; //Have no idea how to deal with those
|
|
322 }
|
|
323 return l;
|
|
324 }
|
|
325
|
|
326
|
|
327 long host2long(String host){
|
|
328 long ip=0;
|
|
329
|
|
330 //check if it's ddd.ddd.ddd.ddd
|
|
331 if(!Character.isDigit(host.charAt(0))) return -1;
|
|
332
|
|
333 int[] addr = ip2intarray(host);
|
|
334 if(addr == null) return -1;
|
|
335
|
|
336 for(int i=0;i<addr.length;++i)
|
|
337 ip += ((long)(addr[i]>=0 ? addr[i] : 0)) << 8*(3-i);
|
|
338
|
|
339 return ip;
|
|
340 }
|
|
341
|
|
342 static int[] ip2intarray(String host){
|
|
343 int[] address = {-1,-1,-1,-1};
|
|
344 int i=0;
|
|
345 StringTokenizer tokens = new StringTokenizer(host,".");
|
|
346 if(tokens.countTokens() > 4) return null;
|
|
347 while(tokens.hasMoreTokens()){
|
|
348 try{
|
|
349 address[i++] = Integer.parseInt(tokens.nextToken()) & 0xFF;
|
|
350 }catch(NumberFormatException nfe){
|
|
351 return null;
|
|
352 }
|
|
353
|
|
354 }
|
|
355 return address;
|
|
356 }
|
|
357
|
|
358
|
|
359 /*
|
|
360 //* This was the test main function
|
|
361 //**********************************
|
|
362
|
|
363 public static void main(String args[])throws UnknownHostException{
|
|
364 int i;
|
|
365
|
|
366 InetRange ir = new InetRange();
|
|
367
|
|
368
|
|
369 for(i=0;i<args.length;++i){
|
|
370 System.out.println("Adding:" + args[i]);
|
|
371 ir.add(args[i]);
|
|
372 }
|
|
373
|
|
374 String host;
|
|
375 java.io.DataInputStream din = new java.io.DataInputStream(System.in);
|
|
376 try{
|
|
377 host = din.readLine();
|
|
378 while(host!=null){
|
|
379 if(ir.contains(host)){
|
|
380 System.out.println("Range contains ip:"+host);
|
|
381 }else{
|
|
382 System.out.println(host+" is not in the range");
|
|
383 }
|
|
384 host = din.readLine();
|
|
385 }
|
|
386 }catch(java.io.IOException io_ex){
|
|
387 io_ex.printStackTrace();
|
|
388 }
|
|
389 }
|
|
390 ********************/
|
|
391
|
|
392 }
|
|
393
|
|
394
|
|
395 class InetRangeResolver implements Runnable{
|
|
396
|
|
397 Object[] entry;
|
|
398
|
|
399 String from, to;
|
|
400
|
|
401 InetRangeResolver(Object[] entry){
|
|
402 this.entry = entry;
|
|
403 from = to = null;
|
|
404 }
|
|
405 InetRangeResolver(Object[] entry,String from,String to){
|
|
406 this.entry = entry;
|
|
407 this.from = from;
|
|
408 this.to = to;
|
|
409 }
|
|
410 public final void resolve(){
|
|
411 resolve(true);
|
|
412 }
|
|
413 public final void resolve(boolean inSeparateThread){
|
|
414 if(inSeparateThread){
|
|
415 Thread t = new Thread(this);
|
|
416 t.start();
|
|
417 }else
|
|
418 run();
|
|
419
|
|
420 }
|
|
421 public void run(){
|
|
422 try{
|
|
423 if(from == null){
|
|
424 InetAddress ip = InetAddress.getByName((String) entry[0]);
|
|
425 entry[1] = ip;
|
|
426 Long l = new Long(InetRange.ip2long(ip));
|
|
427 entry[2] = entry[3] = l;
|
|
428 }else{
|
|
429 InetAddress f = InetAddress.getByName(from);
|
|
430 InetAddress t = InetAddress.getByName(to);
|
|
431 entry[2] = new Long(InetRange.ip2long(f));
|
|
432 entry[3] = new Long(InetRange.ip2long(t));
|
|
433
|
|
434 }
|
|
435 }catch(UnknownHostException uhe){
|
|
436 //System.err.println("Resolve failed for "+from+','+to+','+entry[0]);
|
|
437 }
|
|
438 }
|
|
439
|
|
440 }
|