View Javadoc
1   package net.logAnalyzer.utils;
2   
3   import java.io.BufferedReader;
4   import java.io.FileInputStream;
5   import java.io.FileOutputStream;
6   import java.io.IOException;
7   import java.io.InputStreamReader;
8   import java.io.PrintStream;
9   import java.io.StringReader;
10  import java.net.InetAddress;
11  import java.net.Socket;
12  import java.net.UnknownHostException;
13  import java.util.Properties;
14  
15  /***
16   * This class implements the "Who Is" resolution for IP addresses (IP v4 and IP
17   * v6). It uses a file based cache if exists to increase resolution speed.
18   * <p>
19   * Beware than the cache file is not updated until you call
20   * {@link WhoIs#saveWhoIsCache()}.
21   * </p>
22   * 
23   * @author Karim REFEYTON
24   * @version 0.1
25   */
26  public class WhoIs {
27      /***
28       * Sans réponse.
29       */
30      private static final String NOTFOUND_RESPONSE = "(not found)";
31  
32      /***
33       * File name used to save and reload WhoIs cache.
34       */
35      private static final String WHOISCACHE_FILENAME = "whoIsCache.properties";
36  
37      /***
38       * WhoIs cache.
39       */
40      private static Properties whoIsCache = null;
41  
42      /***
43       * Address to resolve.
44       */
45      private InetAddress address = null;
46  
47      /***
48       * WhoIs servers names. List of WhoIs servers :
49       * <ul>
50       * <li><tt>whois.ripe.net</tt>: <a href="http://www.ripe.net">RIPE NCC
51       * (Réseaux IP Européens) </a>– Europe, the Middle East, and Central Asia</li>
52       * <li><tt>ws.arin.net</tt>: <a href="http://www.arin.net">ARIN
53       * (American Registry for Internet Numbers) </a>– North America Region </li>
54       * <li><tt>whois.apnic.net</tt>: <a href="http://www.apnic.net">APNIC
55       * (Asia Pacific Network Information Centre) </a>– Asia/Pacific Region</li>
56       * <li><tt>whois.afrinic.net</tt>: <a
57       * href="http://www.afrinic.net">AfriNIC (African Network Information
58       * Centre) </a>– Africa Region </li>
59       * <li><tt>whois.lacnic.net</tt>: <a href="http://lacnic.net">LACNIC
60       * (Regional Latin-American and Caribbean IP Address Registry) </a>– Latin
61       * America and some Caribbean Islands</li>
62       * </ul>
63       */
64      public static final String[] WHOIS_SERVERS_NAMES = new String[] {
65              "whois.ripe.net", "ws.arin.net", "whois.apnic.net",
66              "whois.afrinic.net", "whois.lacnic.net" };
67  
68      /***
69       * WhoIs servers IP.
70       */
71      public static final String[] WHOIS_SERVERS_IP = new String[] {
72              "193.0.0.135", "ws.arin.net", "202.12.29.13", "whois.afrinic.net",
73              "200.160.2.15" };
74  
75      /***
76       * Currently used index of WhoIs server. <tt>-1</tt> if the server is
77       * specified to the constructor.
78       */
79      private int whoIsServerIndex = 0;
80  
81      /***
82       * WhoIs server name if specified ot the constructor.
83       */
84      private String whoIsServerName = null;
85  
86      /***
87       * <tt>true</tt> if the address is a new address.
88       */
89      private boolean isnew = false;
90  
91      /***
92       * Constructs a new WhoIs resolution for the specified address. Uses only
93       * known WhoIs servers {@link #WHOIS_SERVERS_NAMES}.
94       * 
95       * @param address
96       *            Address to resolve.
97       */
98      public WhoIs(String address) throws UnknownHostException {
99          this.address = InetAddress.getByName(address);
100         this.whoIsServerIndex = 0;
101         loadWhoIsCache();
102         getFullResponse();
103     }
104 
105     /***
106      * Constructs a new WhoIs resolution for the specified address. Uses first
107      * the specified whoIsServerName and, if not found, the known WhoIs servers
108      * {@link #WHOIS_SERVERS_NAMES}.
109      * 
110      * @param address
111      *            Address to resolve.
112      * @param whoIsServerName
113      *            WhoIs server to use first.
114      */
115     public WhoIs(String address, String whoIsServerName)
116             throws UnknownHostException {
117         this.address = InetAddress.getByName(address);
118         this.whoIsServerIndex = -1;
119         this.whoIsServerName = whoIsServerName;
120         getFullResponse();
121     }
122 
123     /***
124      * Adds a resolution to the cache.
125      * 
126      * @param response
127      *            Reponse to add to cache.
128      */
129     private void addToWhoIsCache(String response) {
130         // Adds the response to cache
131         whoIsCache.setProperty(getAddress(), response);
132     }
133 
134     /***
135      * Loads WhoIs cache from a file. The file name is
136      * {@link #WHOISCACHE_FILENAME}.
137      */
138     private void loadWhoIsCache() {
139         if (whoIsCache == null) {
140             // whoIsCache = new Hashtable();
141             whoIsCache = new Properties();
142             try {
143                 whoIsCache.load(new FileInputStream(WHOISCACHE_FILENAME));
144             } catch (IOException ioe) {
145                 whoIsCache.clear();
146             }
147         }
148     }
149 
150     /***
151      * Saves WhoIs cache to a file. The file name is
152      * {@link #WHOISCACHE_FILENAME}.
153      */
154     public static void saveWhoIsCache() {
155         // Saves the cache
156         if (whoIsCache != null) {
157             try {
158                 whoIsCache.store(new FileOutputStream(WHOISCACHE_FILENAME), "");
159             } catch (IOException ioe) {
160                 // NOP
161             }
162         }
163     }
164 
165     /***
166      * Returns the address to resolve.
167      * 
168      * @return IP address to resolve in String format.
169      */
170     public String getAddress() {
171         return this.address.getHostAddress();
172     }
173 
174     /***
175      * Returns the address to resolve.
176      * 
177      * @return IP address to resolve.
178      */
179     public InetAddress getInetAddress() {
180         return this.address;
181     }
182 
183     /***
184      * Returns the IP of the server used to resolve the address.
185      * 
186      * @return WhoIs server IP.
187      */
188     public String getWhoIsServerIP() {
189         if (whoIsServerIndex == -1) {
190             return whoIsServerName;
191         } else {
192             return WHOIS_SERVERS_IP[whoIsServerIndex];
193         }
194     }
195 
196     /***
197      * Returns the name of the server used to resolve the address.
198      * 
199      * @return WhoIs server name.
200      */
201     public String getWhoIsServerName() {
202         if (whoIsServerIndex == -1) {
203             return whoIsServerName;
204         } else {
205             return WHOIS_SERVERS_NAMES[whoIsServerIndex];
206         }
207     }
208 
209     /***
210      * Returns the full response of the WhoIs server.
211      * 
212      * @return Full response.
213      */
214     public String getFullResponse() {
215         String fullResponse = (String) whoIsCache.getProperty(getAddress(),
216                 null);
217         if (fullResponse == null || fullResponse.equals("")) {
218             isnew = (fullResponse == null);
219             Socket whoIsSocket = null;
220             try {
221                 StringBuffer response = new StringBuffer();
222                 // Creates socket if needed
223                 whoIsSocket = new Socket(getWhoIsServerIP(), 43);
224                 BufferedReader input = new BufferedReader(
225                         new InputStreamReader(whoIsSocket.getInputStream()));
226                 PrintStream output = new PrintStream(whoIsSocket
227                         .getOutputStream());
228                 // Asks for whois request
229                 output.println(getAddress());
230                 // Reads the server response
231                 String line;
232                 while ((line = input.readLine()) != null) {
233                     if (!line.equals("") && !line.startsWith("%")) {
234                         response.append(line).append('\n');
235                     }
236                 }
237                 fullResponse = response.toString();
238                 // If nof found, tries with the next whois server
239                 String netName = getNetName(fullResponse);
240                 if (whoIsServerIndex != -1
241                         && (netName == null || netName.equals("")
242                                 || netName.equalsIgnoreCase("IANA-BLK") || netName
243                                 .equalsIgnoreCase("ARIN-CIDR-BLOCK"))) {
244                     if (whoIsServerIndex < WHOIS_SERVERS_NAMES.length - 1) {
245                         // Tries with the next whois server
246                         whoIsServerIndex++;
247                         fullResponse = null;
248                         return getFullResponse();
249                     } else if (whoIsServerName != null) {
250                         // No more server and a name was specified in
251                         // constructor
252                         whoIsServerIndex = -1;
253                         fullResponse = NOTFOUND_RESPONSE;
254                     } else {
255                         // No more server
256                         whoIsServerIndex = 0;
257                         fullResponse = NOTFOUND_RESPONSE;
258                     }
259                 }
260             } catch (IOException ioe) {
261                 // System.err.println(ioe.getMessage());
262                 // System.exit(1);
263                 fullResponse = NOTFOUND_RESPONSE;
264             } catch (NullPointerException npe) {
265                 // System.err.println(npe.getMessage());
266                 // System.exit(1);
267                 fullResponse = NOTFOUND_RESPONSE;
268             } finally {
269                 // Closes socket
270                 if (whoIsSocket != null) {
271                     try {
272                         whoIsSocket.close();
273                     } catch (IOException ioe) {
274                         // NOP
275                         whoIsSocket = null;
276                     }
277                 }
278                 // Puts the response in the cache if not empty
279                 if (fullResponse != null && !"".equals(fullResponse)) {
280                     addToWhoIsCache(fullResponse);
281                 }
282             }
283         } else {
284             isnew = false;
285         }
286         return fullResponse;
287     }
288 
289     /***
290      * Returns the CIDR address. Looks at <tt>CIDR</tt> or <tt>route</tt>
291      * information.
292      * 
293      * @return Orgnization name.
294      */
295     public String getCIDR() {
296         String cidr = getInfo(getFullResponse(),
297                 new String[] { "CIDR", "route" });
298         if (cidr != null) {
299             int pos = cidr.indexOf('/');
300             if (pos >= 0) {
301                 cidr = cidr.substring(0, pos);
302             }
303         }
304         return cidr;
305     }
306 
307     /***
308      * Returns the coutrny. Looks at <tt>coutrny</tt> or <tt>net-name</tt>
309      * information.
310      * 
311      * @return Country.
312      */
313     public String getCountry() {
314         return getInfo(getFullResponse(), new String[] { "country" });
315     }
316 
317     /***
318      * Returns the network name. Looks at <tt>netname</tt> or
319      * <tt>net-name</tt> information.
320      * 
321      * @return Orgnization name.
322      */
323     public String getNetName() {
324         String netName = getInfo(getFullResponse(), new String[] { "netname",
325                 "net-name" });
326         return netName;
327     }
328 
329     /***
330      * Returns the network name. Looks at <tt>netname</tt> or
331      * <tt>net-name</tt> information.
332      * 
333      * @param response
334      *            Response to parse.
335      * @return Orgnization name.
336      */
337     public String getNetName(String response) {
338         String netName = getInfo(response,
339                 new String[] { "netname", "net-name" });
340         return netName;
341     }
342 
343     /***
344      * Returns the organization name. Looks at <tt>org-name</tt> or
345      * <tt>orgname</tt> or the first <tt>descr</tt> information.
346      * 
347      * @return Orgnization name.
348      */
349     public String getOrgName() {
350         String orgName = getInfo(getFullResponse(), new String[] { "org-name",
351                 "OrgName", "descr" });
352         return orgName;
353     }
354 
355     /***
356      * Returns an information from the specified response. Looks at the
357      * specified infos in order. If the first is found, returns the first info
358      * content. Otherwise, if the second is found, returns the second info
359      * content, etc...
360      * 
361      * @param response
362      *            Response to parse.
363      * @param infos
364      *            Infos to search in priority order.
365      * @return Info content if found; <tt>null</tt> otherwise.
366      */
367     private String getInfo(String response, String[] infos) {
368         String infoContent = null;
369         try {
370             BufferedReader reader = new BufferedReader(new StringReader(
371                     response));
372             String line = "";
373             boolean mainInfoFound = false;
374             String[] infosContents = new String[infos.length];
375             // Parses the full report, looking for specified infos
376             // The first info (infoFoundIndec == 0) has the priority
377             while (!mainInfoFound && (line = reader.readLine()) != null) {
378                 String ucLine = line.toUpperCase();
379                 for (int i = 0; i < infos.length; i++) {
380                     if (infosContents[i] == null) {
381                         String ucInfo = infos[i].toUpperCase();
382                         if (ucLine.startsWith(ucInfo)) {
383                             // Info found
384                             infosContents[i] = line.substring(
385                                     ucLine.indexOf(' ', ucInfo.length()) + 1)
386                                     .trim();
387                             mainInfoFound = (i == 0);
388                         }
389                     }
390                 }
391             }
392             for (int i = 0; infoContent == null && i < infosContents.length; i++) {
393                 infoContent = infosContents[i];
394             }
395             reader.close();
396         } catch (IOException ioe) {
397             // NOP
398             infoContent = null;
399         }
400 
401         return infoContent;
402     }
403 
404     /***
405      * Returns <tt>true</tt> is a new address (ie if the address was not in
406      * cache).
407      * 
408      * @return <tt>true</tt> if it is a new address; <tt>false</tt>
409      *         otherwise.
410      */
411     public boolean isNew() {
412         return this.isnew;
413     }
414 }