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.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.ProxyException;
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.
* @throws ProxyException on error.
************************************************************************/
public ProxySelector getProxySelector() throws ProxyException {
try {
Logger.log(getClass(), LogLevel.TRACE, "Using WPAD to find a proxy");
String pacScriptUrl = detectScriptUrlPerDHCP();
if (pacScriptUrl == null) {
pacScriptUrl = detectScriptUrlPerDNS();
}
if (pacScriptUrl == null) {
return null;
}
Logger.log(getClass(), LogLevel.TRACE, "PAC script url found: {0}", pacScriptUrl);
return ProxyUtil.buildPacSelectorForUrl(pacScriptUrl);
} catch (IOException e) {
Logger.log(getClass(), LogLevel.ERROR, "Error during WPAD search.", e);
throw new ProxyException(e);
}
}
/*************************************************************************
* Loads the settings and stores them in a properties map.
* @return the settings.
************************************************************************/
public Properties readSettings() {
try {
String pacScriptUrl = detectScriptUrlPerDHCP();
if (pacScriptUrl == null) {
pacScriptUrl = detectScriptUrlPerDNS();
}
if (pacScriptUrl == null) {
return null;
}
Properties result = new Properties();
result.setProperty("url", pacScriptUrl);
return result;
} catch (IOException e) {
// Ignore and return empty properties.
return new Properties();
}
}
/*************************************************************************
* 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() throws IOException {
String result = null;
// String fqdn = InetAddress.getLocalHost().getCanonicalHostName();
Logger.log(getClass(), LogLevel.TRACE, "Searching per DNS guessing.");
// Logger.log(getClass(), LogLevel.INFO, "fqdn: ", fqdn);
/** Reading address from "/etc/resolv.conf"; file looks like:
*
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 127.0.1.1
search ruf.uni-freiburg.de lp.ruf.uni-freiburg.de
*/
FileReader fr = new FileReader("/etc/resolv.conf");
BufferedReader br = new BufferedReader(fr);
String input;
String[] addresses = null;
// using the 4th line of the file.
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;
}
}
if (addresses == null) {
addresses = new String[]{""};
}
for (int i = 0; i < addresses.length; ++i) {
String address = addresses[i];
int index = -1;
do {
if (index != -1) {
address = address.substring(index);
} else {
address = "";
}
// Try to connect to URL
try {
address = ".uni-freiburg.de";
URL lookupURL = new URL("http://wpad"+ address +"/wpad.dat");
Logger.log(getClass(), LogLevel.TRACE, "Trying url: {0}", lookupURL);
HttpURLConnection con = (HttpURLConnection) lookupURL.openConnection(Proxy.NO_PROXY);
con.setInstanceFollowRedirects(true);
con.setRequestProperty("accept", "application/x-ns-proxy-autoconfig");
if (con.getResponseCode() == 200) {
result = lookupURL.toString();
return result;
}
con.disconnect();
} catch (UnknownHostException e) {
Logger.log(getClass(), LogLevel.DEBUG, "Not available!");
// Not a real error, try next address
}
if (address.length() == 0) {
break;
}
index = address.indexOf('.', 1);
} while (true);
}
return null;
}
/*************************************************************************
* Uses DHCP to find the script URL.
* @return the URL, null if not found.
************************************************************************/
private String detectScriptUrlPerDHCP() {
Logger.log(getClass(), LogLevel.DEBUG, "Searching per DHCP not supported yet.");
// TODO Rossi 28.04.2009 Not implemented yet.
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 (ProxyException e) {
// TODO bjoern 28.10.2014 Auto-generated catch block
e.printStackTrace();
} 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);
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);
}
}
}