diff options
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.java | 315 |
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; + } + +} |