summaryrefslogblamecommitdiffstats
path: root/src/main/java/com/btr/proxy/search/wpad/WpadProxySearchStrategy.java
blob: e559d625b532576969aee447deedf6616caf8e67 (plain) (tree)
1
2
3
4
5
6
7
8
9








                                  
                            






                                   
                                     





                                                

                                    


                                                                               











                                                                                  
       
   



                                                                              
 


                                                                                  
 


                                          
 
                                                                                  
                                                    
                                                                    
           
                                                                     

                                                                                  

                                                                                     
 


                                                              
                 

                                                                                                  
         
 

                                                                                  
           

                                                                                  
 
                                          


                                                              
                 


                                                        



                                                                                  


                                                                                 

                                                                                  
 
                                                

                                                                                   
                                                                                      

                           
 







                                                                                 
                                                            
                 
                                                                                                                      





                                                                                               
                                          
                     

                                                                           






                                                                                                            
                         

                                                                                             
                           



                                               
                 
 
                                        
                                                        
                 
 
                                                            

                                                                                                             
                                         
                            








                                                                                     
                                              

                                       
 


                            



















                                                                                                             

                            
 
                                   
                                                                   
                                                                             
                                                                                                    



                                                                                           
 


                                                                                                                

                                                                                                                   
                         



                                                                            
 


                                                                                                   
 



                                                             
 
                                                                










                                                                                                                             
                 
 


         
package com.btr.proxy.search.wpad;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Properties;

import com.btr.proxy.search.ProxySearchStrategy;
import com.btr.proxy.util.Logger;
import com.btr.proxy.util.Logger.LogLevel;
import com.btr.proxy.util.ProxyUtil;

/*****************************************************************************
 * Uses automatic proxy script search (WPAD) to find an PAC file automatically.
 * <p>
 * Note: at the moment only the DNS name guessing schema is implemented. All
 * others are missing.
 * </p>
 * <p>
 * For more information about WPAD: <a
 * href="http://en.wikipedia.org/wiki/Web_Proxy_Autodiscovery_Protocol"
 * >Web_Proxy_Autodiscovery_Protocol</a>
 * </p>
 * <p>
 * Outdated RFC draft: <a href=
 * "http://www.web-cache.com/Writings/Internet-Drafts/draft-ietf-wrec-wpad-01.txt"
 * >draft-ietf-wrec-wpad-01.txt</a>
 * </p>
 * 
 * @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009
 ****************************************************************************/

public class WpadProxySearchStrategy implements ProxySearchStrategy {

	/*************************************************************************
	 * Constructor
	 ************************************************************************/

	public WpadProxySearchStrategy() {
		super();
	}

	/*************************************************************************
	 * Loads the proxy settings from a PAC file.
	 * The location of the PAC file is determined automatically.
	 * 
	 * @return a configured ProxySelector, null if none is found.
	 ************************************************************************/

	public ProxySelector getProxySelector() {
		Logger.log(getClass(), LogLevel.TRACE, "Using WPAD to find a proxy");

		String pacScriptUrl = detectScriptUrlPerDNS();
		if (pacScriptUrl == null) {
			return null;
		}
		Logger.log(getClass(), LogLevel.TRACE, "PAC script url found: {0}", pacScriptUrl);
		return ProxyUtil.buildPacSelectorForUrl(pacScriptUrl);
	}

	/*************************************************************************
	 * Loads the settings and stores them in a properties map.
	 * 
	 * @return the settings.
	 ************************************************************************/

	public Properties readSettings() {
		String pacScriptUrl = detectScriptUrlPerDNS();
		if (pacScriptUrl == null) {
			return null;
		}
		Properties result = new Properties();
		result.setProperty("url", pacScriptUrl);
		return result;
	}

	/*************************************************************************
	 * Uses DNS to find the script URL.
	 * Attention: this detection method is known to have some severe security
	 * issues.
	 * 
	 * @return the URL, null if not found.
	 ************************************************************************/

	private String detectScriptUrlPerDNS() {
		// TODO: Java way of finding all search domains? Seems not trivial
		// Windows workaround could be running ipconfig /all and parsing...
		Logger.log(getClass(), LogLevel.TRACE, "Searching per DNS guessing.");
		String ret;
		int index;

		ret = tryUrl("http://wpad/wpad.dat");
		if (ret != null)
			return ret;

		String fqdn = null;
		try {
			fqdn = InetAddress.getLocalHost().getCanonicalHostName();
		} catch (UnknownHostException e2) {
			// Not successful, try other methods
		}
		if (fqdn != null && !fqdn.matches("\\d+\\.\\d+\\.\\d+\\.\\d+") && (index = fqdn.indexOf('.')) != -1) {
			ret = tryUrl("http://wpad." + fqdn.substring(index + 1) + "/wpad.dat");
			if (ret != null)
				return ret;
		}

		BufferedReader br = null;
		String[] addresses = null;
		try {
			FileReader fr = new FileReader("/etc/resolv.conf");
			br = new BufferedReader(fr);
			String input;
			while ((input = br.readLine()) != null) {
				if (input.startsWith("search")) {
					// the first one is "search" and afterwards addresses are following.
					addresses = input.substring(6).split(" ");
					break;
				}
			}
		} catch (IOException e1) {
			Logger.log(getClass(), LogLevel.DEBUG, "Could not read resolv.conf");
		} finally {
			try {
				br.close();
			} catch (Exception e) {
			}
		}

		if (addresses == null) {
			addresses = new String[] { "" };
		}

		for (int i = 0; i < addresses.length; ++i) {
			String address = addresses[i].trim().replaceAll("^\\.+", "").replaceAll("\\.+$", "");
			if (address.length() < 4)
				continue;
			do {
				ret = tryUrl("http://wpad." + address + "/wpad.dat");
				if (ret != null)
					return ret;
				// don't construct something like wpad.de....
				index = address.indexOf('.');
				if (index == -1 || index + 7 > address.length())
					break;
				address = address.substring(index + 1);
				if (address.indexOf('.') == -1)
					break;
			} while (true);
		}

		return null;
	}

	private String tryUrl(String url) {
		try {
			URL lookupURL = new URL(url);
			Logger.log(getClass(), LogLevel.DEBUG, "Trying url: {0}", lookupURL);

			HttpURLConnection con = (HttpURLConnection) lookupURL.openConnection(Proxy.NO_PROXY);
			con.setConnectTimeout(1500);
			con.setReadTimeout(2500);
			con.setRequestMethod("HEAD");
			con.setInstanceFollowRedirects(true);
			con.setRequestProperty("accept", "application/x-ns-proxy-autoconfig");
			if (con.getResponseCode() == 200) {
				String result = lookupURL.toString(); 
				return result;
			}
			con.disconnect();
		} catch (Exception e) {
			Logger.log(getClass(), LogLevel.DEBUG, "Not available ({0})", e);
			// Not a real error, try next address
		}
		return null;
	}

	// Main method for testing.
	public static void main(String[] args) throws IOException {
		WpadProxySearchStrategy wPSS = new WpadProxySearchStrategy();
		//		System.setProperty("com.btr.proxy.pac.overrideLocalIP", "10.0.0.1");
		try {
			ProxySelector pS = wPSS.getProxySelector();
			ProxySelector.setDefault(pS);
			List<Proxy> proxyList = pS.select(new URI("http://www.google.de"));

			if (proxyList.isEmpty()) {
				Logger.log(WpadProxySearchStrategy.class, LogLevel.INFO, "ProxyList is empty!");
			} else {
				Logger.log(WpadProxySearchStrategy.class, LogLevel.INFO, "proxyList contains: {0}",
						proxyList.toString());
			}
		} catch (URISyntaxException e) {
			// TODO bjoern 28.10.2014 Auto-generated catch block
			e.printStackTrace();
		}

		URL test = new URL("http://www.google.de");
		URLConnection uc = test.openConnection();
		BufferedReader br = new BufferedReader(new InputStreamReader(uc.getInputStream()));

		String inputLine;
		while ((inputLine = br.readLine()) != null) {
			System.out.println(inputLine);
		}

		Socket socket = new Socket("www.google.de", 80);
		try {
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
			bw.write("GET / HTTP/1.1\r\nHost: www.google.de\r\nConnection: close\r\nAccept-Encoding: *\r\n\r\n");
			bw.flush();

			br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			while ((inputLine = br.readLine()) != null) {
				System.out.println(inputLine);
			}
		} finally {
			socket.close();
		}

	}

}