summaryrefslogtreecommitdiffstats
path: root/src/main/java/com/btr/proxy/search/wpad/WpadProxySearchStrategyWithDHPC.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/btr/proxy/search/wpad/WpadProxySearchStrategyWithDHPC.java')
-rw-r--r--src/main/java/com/btr/proxy/search/wpad/WpadProxySearchStrategyWithDHPC.java315
1 files changed, 315 insertions, 0 deletions
diff --git a/src/main/java/com/btr/proxy/search/wpad/WpadProxySearchStrategyWithDHPC.java b/src/main/java/com/btr/proxy/search/wpad/WpadProxySearchStrategyWithDHPC.java
new file mode 100644
index 0000000..bb56cc0
--- /dev/null
+++ b/src/main/java/com/btr/proxy/search/wpad/WpadProxySearchStrategyWithDHPC.java
@@ -0,0 +1,315 @@
+package com.btr.proxy.search.wpad;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.SocketException;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.Properties;
+import java.util.Random;
+import java.util.StringTokenizer;
+
+import com.btr.proxy.search.ProxySearchStrategy;
+import com.btr.proxy.search.wpad.dhcp.DHCPMessage;
+import com.btr.proxy.search.wpad.dhcp.DHCPOptions;
+import com.btr.proxy.search.wpad.dhcp.DHCPSocket;
+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 WpadProxySearchStrategyWithDHPC implements ProxySearchStrategy {
+ DHCPSocket bindSocket = null;
+ byte hwaddr[] = new byte[16];
+ InetAddress serverIP;
+ int portNum;
+ boolean gSentinel;
+
+ /*************************************************************************
+ * Constructor
+ ************************************************************************/
+
+ public WpadProxySearchStrategyWithDHPC() {
+ 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;
+ // using the 4th line of the file.
+ br.readLine();
+ br.readLine();
+ br.readLine();
+ input = br.readLine();
+
+ String[] addresses = input.split(" ");
+ // the first one is "search" and afterwards addresses are following.
+
+ for (int i = 0; i < addresses.length; ++i) {
+ String address = addresses[i];
+ int index = -1;
+ do {
+ address = address.substring(index + 1);
+
+ // if we are already on TLD level then escape
+ if (address.indexOf('.') == -1) {
+ break;
+ }
+
+ // Try to connect to URL
+ try {
+ 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
+ }
+ index = address.indexOf('.');
+ } while (index != -1);
+ }
+
+ 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.");
+
+ // create socket.
+ try {
+ // bindSocket = new DHCPSocket(DHCPMessage.CLIENT_PORT);
+ // --> Not able to use ports under 1024 without being root.
+ this.bindSocket = new DHCPSocket(1068);
+ } catch (SocketException e) {
+ System.err.println(e);
+ return null;
+ }
+
+
+
+ return null;
+ }
+
+ // Sends DHCPDISCOVER Message and returns server message
+ private DHCPMessage SendDiscover() {
+ DHCPSocket bindSocket = null;
+ try {
+ bindSocket = new DHCPSocket(1068);
+ } catch (SocketException e1) {
+ // TODO bjoern 29.10.2014 Auto-generated catch block
+ e1.printStackTrace();
+ return null;
+ }
+
+ Random ranXid = new Random();
+ DHCPMessage messageOut = new DHCPMessage(DHCPMessage.BROADCAST_ADDR,
+ DHCPMessage.SERVER_PORT);
+ DHCPMessage messageIn = new DHCPMessage(DHCPMessage.BROADCAST_ADDR,
+ DHCPMessage.SERVER_PORT);
+ try {
+ // Specify type of message: 1 = request - message, 2 = reply - message
+ messageOut.setOp((byte) 1);
+ // set Hardware type: 1 = Ethernet, 6 = IEEE 802 Networks, ...
+ messageOut.setHtype((byte) 1); // 1 = ethernet
+ // set hardware address length: 6 for MAC address
+ messageOut.setHlen((byte) 6);
+ messageOut.setHops((byte) 0);
+ // set session ID for later comparing with incoming message.
+ messageOut.setXid(ranXid.nextInt());
+ messageOut.setSecs((short) 0);
+ messageOut.setFlags((short) 0x8000);
+ // set client hardware address, in this case my own hardware address of eth0.
+ messageOut.setChaddr(ChaddrToByte("D8:D3:85:80:8F:C9"));
+
+ byte[] opt = new byte[1];
+ byte[] wpadOpt = new byte[1];
+ opt[0] = DHCPMessage.DHCPDISCOVER;
+
+ // change message type
+ messageOut.setOption(DHCPOptions.OPTION_DHCP_MESSAGE_TYPE, opt);
+ wpadOpt[0] = DHCPMessage.OPTION_DHCP_WPAD;
+ messageOut.setOption(DHCPOptions.OPTION_DHCP_PARAMETER_REQUEST_LIST, wpadOpt);
+// messageOut.setOption(DHCPOptions.OPTION_DHCP_IP_ADRESS_REQUESTED,
+// offerMessageIn.getYiaddr());
+
+ bindSocket.send(messageOut); // send DHCPREQUEST
+ System.out.println("Sending DHCPDISCOVER ...");
+ boolean sentinal = true;
+ int counter = 0;
+ while (sentinal) {
+ if (counter == 2) { return null; }
+ if (bindSocket.receive(messageIn)) {
+ if (messageOut.getXid() == messageIn.getXid()) {
+ sentinal = false;
+ } else {
+ bindSocket.send(messageOut);
+ counter++;
+ }
+ } else {
+ bindSocket.send(messageOut);
+ counter++;
+ }
+ }
+ } catch (SocketException e) {
+ System.err.println(e);
+ return null;
+ } catch (IOException e) {
+ System.err.println(e);
+ return null;
+ } finally {
+ try {
+ bindSocket.close();
+ } catch (Exception e) {
+ // do nothing.
+ }
+ } // end catch
+ return messageIn;
+ }
+
+ // Main method for testing.
+ public static void main(String[] args) throws UnsupportedEncodingException {
+ WpadProxySearchStrategyWithDHPC wPSSDHCP = new WpadProxySearchStrategyWithDHPC();
+ DHCPMessage serverAnswer = wPSSDHCP.SendDiscover();
+
+ Logger.log(WpadProxySearchStrategyWithDHPC.class, LogLevel.INFO,
+ "DHCP serverAnswer: {0}", new String(serverAnswer.getOption(DHCPMessage.OPTION_DHCP_WPAD), "UTF-8"));
+ }
+
+ private byte[] ChaddrToByte(String inChaddr) {
+ StringTokenizer token = new StringTokenizer(inChaddr, ":");
+ Integer tempInt = new Integer(0);
+ byte outHwaddr[] = new byte[16];
+ int temp;
+ int i = 0;
+ while (i < 6) {
+ temp = tempInt.parseInt(token.nextToken(), 16);
+ outHwaddr[i] = (byte) temp;
+ i++;
+ }
+ return outHwaddr;
+ }
+
+}