diff options
Diffstat (limited to 'src/main/java/com/btr/proxy/search/wpad')
5 files changed, 1771 insertions, 0 deletions
diff --git a/src/main/java/com/btr/proxy/search/wpad/WpadProxySearchStrategy.java b/src/main/java/com/btr/proxy/search/wpad/WpadProxySearchStrategy.java new file mode 100644 index 0000000..cf01fd3 --- /dev/null +++ b/src/main/java/com/btr/proxy/search/wpad/WpadProxySearchStrategy.java @@ -0,0 +1,234 @@ +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); + } + + } + +} 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; + } + +} diff --git a/src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPMessage.java b/src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPMessage.java new file mode 100644 index 0000000..86323d5 --- /dev/null +++ b/src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPMessage.java @@ -0,0 +1,880 @@ +package com.btr.proxy.search.wpad.dhcp; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * This class represents a DHCP Message. + * + * @author Jason Goldschmidt, Nick Stone and Simon Frankenberger + */ +public class DHCPMessage { + // ----------------------------------------------------------- + // Constants + // ----------------------------------------------------------- + /** + * Operation for a request + */ + public static final byte OP_REQUEST = 1; + + /** + * Operation for a reply + */ + public static final byte OP_REPLY = 2; + + /** + * Message Code representing a DHCPDISCOVER message + */ + public static final byte DHCPDISCOVER = 1; + + /** + * Message Code representing a DHCPOFFER message + */ + public static final byte DHCPOFFER = 2; + + /** + * Message Code representing a DHCPREQUEST message + */ + public static final byte DHCPREQUEST = 3; + + /** + * Message Code representing a DHCPDECLINE message + */ + public static final byte DHCPDECLINE = 4; + + /** + * Message Code representing a DHCPACK message + */ + public static final byte DHCPACK = 5; + + /** + * Message Code representing a DHCPNAK message + */ + public static final byte DHCPNAK = 6; + + /** + * Message Code representing a DHCPRELEASE message + */ + public static final byte DHCPRELEASE = 7; + + /** + * Message Code representing a DHCPINFORM message + */ + public static final byte DHCPINFORM = 8; + + /** + * Default DHCP client port + */ + public static final int CLIENT_PORT = 68; // client port (by default) + + /** + * Default DHCP server port + */ + public static final int SERVER_PORT = 67; // server port (by default) + + /** + * Broadcast Adress to send packets to + */ + public static InetAddress BROADCAST_ADDR = null; + + public static final byte OPTION_DHCP_WPAD = (byte) 252; + + + + // ----------------------------------------------------------- + // Fields defining a dhcp message + // ----------------------------------------------------------- + /** + * Operation Code.<br> + * <br> + * Can either be {@link #OP_REQUEST} or {@link #OP_REPLY}. + */ + private byte op; + + /** + * Networktype as defined by + * <a href="http://tools.ietf.org/html/rfc1340#page-54">RFC1340 page 54</a>. + */ + private byte htype; + + /** + * Hardware address length (e.g. '6' for ethernet). + */ + private byte hlen; + + /** + * Client sets to zero, optionally used by relay-agents + * when booting via a relay-agent. + */ + private byte hops; + + /** + * Transaction ID, a random number chosen by the + * client, used by the client and server to associate + * messages and responses between a client and a + * server. + */ + private int xid; + + /** + * Filled in by client, seconds elapsed since client + * started trying to boot. + */ + private short secs; + + /** + * Flags for this message.<br> + * The leftmost bit is defined as the BROADCAST (B) flag. + */ + private short flags; + + /** + * Client IP address; filled in by client in + * DHCPREQUEST if verifying previously allocated + * configuration parameters. + */ + private byte ciaddr[] = new byte[4]; + + /** + * 'your' (client) IP address. + */ + private byte yiaddr[] = new byte[4]; + + /** + * IP address of next server to use in bootstrap; + * returned in DHCPOFFER, DHCPACK and DHCPNAK by + * server. + */ + private byte siaddr[] = new byte[4]; + + /** + * Relay agent IP address, used in booting via a + * relay-agent. + */ + private byte giaddr[] = new byte[4]; + + /** + * Client hardware address. + */ + private byte chaddr[] = new byte[16]; + + /** + * Optional server host name, null terminated string. + */ + private byte sname[] = new byte[64]; + + /** + * Boot file name, null terminated string; "generic" + * name or null in DHCPDISCOVER, fully qualified + * directory-path name in DHCPOFFER. + */ + private byte file[] = new byte[128]; + + /** + * Internal representation of the given DHCP options. + */ + private DHCPOptions optionsList = null; + + /** + * global port variable for this message + */ + private int gPort; + + /** + * The destination IP-Adress of this message + */ + private InetAddress destination_IP; + + static { + try { + BROADCAST_ADDR = InetAddress.getByName("255.255.255.255"); + // broadcast address(by default) + } + catch (UnknownHostException e) { + // Broadcast address must always exist + } + } + + // ----------------------------------------------------------- + // Constructors + // ----------------------------------------------------------- + + /** + * Creates empty DHCPMessage object, + * initializes the object, sets the host to the broadcast address, + * the local subnet, binds to the default server port. + */ + public DHCPMessage() { + initialize(); + + this.destination_IP = BROADCAST_ADDR; + this.gPort = SERVER_PORT; + } + + /** + * Copy constructor + * creates DHCPMessage from inMessage + * + * @param inMessage The message to be copied + */ + public DHCPMessage(DHCPMessage inMessage) { + initialize(); + + this.destination_IP = BROADCAST_ADDR; + this.gPort = SERVER_PORT; + this.op = inMessage.getOp(); + this.htype = inMessage.getHtype(); + this.hlen = inMessage.getHlen(); + this.hops = inMessage.getHops(); + this.xid = inMessage.getXid(); + this.secs = inMessage.getSecs(); + this.flags = inMessage.getFlags(); + this.ciaddr = inMessage.getCiaddr(); + this.yiaddr = inMessage.getYiaddr(); + this.siaddr = inMessage.getSiaddr(); + this.giaddr = inMessage.getGiaddr(); + this.chaddr = inMessage.getChaddr(); + this.sname = inMessage.getSname(); + this.file = inMessage.getFile(); + this.optionsList.internalize(inMessage.getOptions()); + } + + /** + * Copy constructor + * creates DHCPMessage from inMessage and sets server and port. + * + * @param inMessage The message to be copied + * @param inServername The host name + * @param inPort The port number + */ + public DHCPMessage(DHCPMessage inMessage, InetAddress inServername, int inPort) { + initialize(); + + this.destination_IP = inServername; + this.gPort = inPort; + + this.op = inMessage.getOp(); + this.htype = inMessage.getHtype(); + this.hlen = inMessage.getHlen(); + this.hops = inMessage.getHops(); + this.xid = inMessage.getXid(); + this.secs = inMessage.getSecs(); + this.flags = inMessage.getFlags(); + this.ciaddr = inMessage.getCiaddr(); + this.yiaddr = inMessage.getYiaddr(); + this.siaddr = inMessage.getSiaddr(); + this.giaddr = inMessage.getGiaddr(); + this.chaddr = inMessage.getChaddr(); + this.sname = inMessage.getSname(); + this.file = inMessage.getFile(); + this.optionsList.internalize(inMessage.getOptions()); + } + + /** + * Copy constructor + * creates DHCPMessage from inMessage and sets server name. + * + * @param inMessage The message to be copied + * @param inServername The host name + */ + public DHCPMessage(DHCPMessage inMessage, InetAddress inServername) { + initialize(); + + this.destination_IP = inServername; + this.gPort = SERVER_PORT; + + this.op = inMessage.getOp(); + this.htype = inMessage.getHtype(); + this.hlen = inMessage.getHlen(); + this.hops = inMessage.getHops(); + this.xid = inMessage.getXid(); + this.secs = inMessage.getSecs(); + this.flags = inMessage.getFlags(); + this.ciaddr = inMessage.getCiaddr(); + this.yiaddr = inMessage.getYiaddr(); + this.siaddr = inMessage.getSiaddr(); + this.giaddr = inMessage.getGiaddr(); + this.chaddr = inMessage.getChaddr(); + this.sname = inMessage.getSname(); + this.file = inMessage.getFile(); + this.optionsList.internalize(inMessage.getOptions()); + } + + /** + * Creates an empty DHCPMessage object, + * initializes the object, sets the host to a specified host name, + * and binds to a specified port. + * + * @param inServername The host name + * @param inPort The port number + */ + public DHCPMessage(InetAddress inServername, int inPort) { + initialize(); + + this.destination_IP = inServername; + this.gPort = inPort; + } + + /** + * Creates an empty DHCPMessage object, + * initializes the object, sets the host to a specified host name, + * and binds to the default port. + * + * @param inServername The host name + */ + public DHCPMessage(InetAddress inServername) { + initialize(); + + this.destination_IP = inServername; + this.gPort = SERVER_PORT; + } + + /** + * Creates an empty DHCPMessage object, + * initializes the object, sets the host to the broadcast address, + * and binds to a specified port. + * + * @param inPort The port number + */ + public DHCPMessage(int inPort) { + initialize(); + + this.destination_IP = BROADCAST_ADDR; + this.gPort = inPort; + } + + /** + * Creates an empty DHCPMessage object, + * initializes the object with a specified byte array containing + * DHCP message information, sets the host to default host name, the + * local subnet, and bind to the default server port. + * + * @param ibuf The byte array to initialize DHCPMessage object + */ + public DHCPMessage(byte[] ibuf) { + initialize(); + internalize(ibuf); + + this.destination_IP = BROADCAST_ADDR; + this.gPort = SERVER_PORT; + } + + /** + * Creates an empty DHCPMessage object, + * initializes the object with a specified byte array containing + * DHCP message information, sets the host to specified host name, + * and binds to the specified port. + * + * @param ibuf The byte array to initialize DHCPMessage object + * @param inServername The hostname + * @param inPort The port number + */ + public DHCPMessage(byte[] ibuf, InetAddress inServername, int inPort) { + initialize(); + internalize(ibuf); + + this.destination_IP = inServername; + this.gPort = inPort; + } + + /** + * Creates an empty DHCPMessage object, + * initializes the object with a specified byte array containing + * DHCP message information, sets the host to broadcast address, + * and binds to the specified port. + * + * @param ibuf The byte array to initialize DHCPMessage object + * @param inPort The port number + */ + public DHCPMessage(byte ibuf[], int inPort) { + initialize(); + internalize(ibuf); + + this.destination_IP = BROADCAST_ADDR; + this.gPort = inPort; + } + + /** + * Creates an empty DHCPMessage object, + * initializes the object with a specified byte array containing + * DHCP message information, sets the host to specified host name, + * and binds to the specified port. + * + * @param ibuf The byte array to initialize DHCPMessage object + * @param inServername The hostname + */ + public DHCPMessage(byte[] ibuf, InetAddress inServername) { + initialize(); + internalize(ibuf); + + this.destination_IP = inServername; + this.gPort = SERVER_PORT; + } + + /** + * Creates a new DHCPMessage object from the giben DataInputStream. + * + * @param inStream The stream to read from + */ + public DHCPMessage(DataInputStream inStream) { + initialize(); + + try { + this.op = inStream.readByte(); + this.htype = inStream.readByte(); + this.hlen = inStream.readByte(); + this.hops = inStream.readByte(); + this.xid = inStream.readInt(); + this.secs = inStream.readShort(); + this.flags = inStream.readShort(); + inStream.readFully(this.ciaddr, 0, 4); + inStream.readFully(this.yiaddr, 0, 4); + inStream.readFully(this.siaddr, 0, 4); + inStream.readFully(this.giaddr, 0, 4); + inStream.readFully(this.chaddr, 0, 16); + inStream.readFully(this.sname, 0, 64); + inStream.readFully(this.file, 0, 128); + byte[] options = new byte[312]; + inStream.readFully(options, 0, 312); + this.optionsList.internalize(options); + } + catch (IOException e) { + System.err.println(e); + } + } + + // ----------------------------------------------------------- + // Methods + // ----------------------------------------------------------- + /** + * Initializes datamembers in the constructors + * every empty DHCPMessage object will by default contain these params. + * Initializes options array from linked list form. + */ + private void initialize() { + this.optionsList = new DHCPOptions(); + } + + /** + * Converts a DHCPMessage object to a byte array. + * + * @return A byte array with information from DHCPMessage object, + * ready to send. + */ + public synchronized byte[] externalize() { + ByteArrayOutputStream outBStream = new ByteArrayOutputStream(); + DataOutputStream outStream = new DataOutputStream(outBStream); + + try { + outStream.writeByte(this.op); + outStream.writeByte(this.htype); + outStream.writeByte(this.hlen); + outStream.writeByte(this.hops); + outStream.writeInt(this.xid); + outStream.writeShort(this.secs); + outStream.writeShort(this.flags); + outStream.write(this.ciaddr, 0, 4); + outStream.write(this.yiaddr, 0, 4); + outStream.write(this.siaddr, 0, 4); + outStream.write(this.giaddr, 0, 4); + outStream.write(this.chaddr, 0, 16); + outStream.write(this.sname, 0, 64); + outStream.write(this.file, 0, 128); + + byte[] options = new byte[312]; + if (this.optionsList == null) { + initialize(); + } + + options = this.optionsList.externalize(); + outStream.write(options, 0, 312); + } catch (IOException e) { + System.err.println(e); + } + + // extract the byte array from the Stream + byte data[] = outBStream.toByteArray(); + + return data; + } + + /** + * Convert a specified byte array containing a DHCP message into a + * DHCPMessage object. + * + * @param ibuff Byte array to convert to a DHCPMessage object + * @return A DHCPMessage object with information from byte array. + */ + + public synchronized DHCPMessage internalize(byte[] ibuff) { + ByteArrayInputStream inBStream = + new ByteArrayInputStream(ibuff, 0, ibuff.length); + DataInputStream inStream = new DataInputStream(inBStream); + + try { + this.op = inStream.readByte(); + this.htype = inStream.readByte(); + this.hlen = inStream.readByte(); + this.hops = inStream.readByte(); + this.xid = inStream.readInt(); + this.secs = inStream.readShort(); + this.flags = inStream.readShort(); + inStream.readFully(this.ciaddr, 0, 4); + inStream.readFully(this.yiaddr, 0, 4); + inStream.readFully(this.siaddr, 0, 4); + inStream.readFully(this.giaddr, 0, 4); + inStream.readFully(this.chaddr, 0, 16); + inStream.readFully(this.sname, 0, 64); + inStream.readFully(this.file, 0, 128); + + byte[] options = new byte[312]; + inStream.readFully(options, 0, 312); + if (this.optionsList == null) { + initialize(); + } + + this.optionsList.internalize(options); + } + catch (IOException e) { + System.err.println(e); + } // end catch + + return this; + } + + /** + * Set message Op code / message type. + * + * @param inOp message Op code / message type + */ + public void setOp(byte inOp) { + this.op = inOp; + } + + /** + * Set hardware address type. + * + * @param inHtype hardware address type + */ + public void setHtype(byte inHtype) { + this.htype = inHtype; + } + + /** + * Set hardware address length. + * + * @param inHlen hardware address length + */ + public void setHlen(byte inHlen) { + this.hlen = inHlen; + } + + /** + * Set hops field. + * + * @param inHops hops field + */ + public void setHops(byte inHops) { + this.hops = inHops; + } + + /** + * Set transaction ID. + * + * @param inXid transactionID + */ + public void setXid(int inXid) { + this.xid = inXid; + } + + /** + * Set seconds elapsed since client began address acquisition or + * renewal process. + * + * @param inSecs Seconds elapsed since client began address acquisition + * or renewal process + */ + public void setSecs(short inSecs) { + this.secs = inSecs; + } + + /** + * Set flags field. + * + * @param inFlags flags field + */ + public void setFlags(short inFlags) { + this.flags = inFlags; + } + + /** + * Set client IP address. + * + * @param inCiaddr client IP address + */ + public void setCiaddr(byte[] inCiaddr) { + this.ciaddr = inCiaddr; + } + + /** + * Set 'your' (client) IP address. + * + * @param inYiaddr 'your' (client) IP address + */ + public void setYiaddr(byte[] inYiaddr) { + this.yiaddr = inYiaddr; + } + + /** + * Set address of next server to use in bootstrap. + * + * @param inSiaddr address of next server to use in bootstrap + */ + public void setSiaddr(byte[] inSiaddr) { + this.siaddr = inSiaddr; + } + + /** + * Set relay agent IP address. + * + * @param inGiaddr relay agent IP address + */ + public void setGiaddr(byte[] inGiaddr) { + this.giaddr = inGiaddr; + } + + /** + * Set client harware address. + * + * @param inChaddr client hardware address + */ + public void setChaddr(byte[] inChaddr) { + this.chaddr = inChaddr; + } + + /** + * Set optional server host name. + * + * @param inSname server host name + */ + public void setSname(byte[] inSname) { + this.sname = inSname; + } + + /** + * Set boot file name. + * + * @param inFile boot file name + */ + public void setFile(byte[] inFile) { + this.file = inFile; + } + + /** + * Set message destination port. + * + * @param inPortNum port on message destination host + */ + public void setPort(int inPortNum) { + this.gPort = inPortNum; + } + + /** + * Set message destination IP + * @param inHost string representation of message destination IP or + * hostname + */ + public void setDestinationHost(String inHost) { + try { + this.destination_IP = InetAddress.getByName(inHost); + } + catch (Exception e) { + System.err.println(e); + } + } + + /** + * @return message Op code / message type. + */ + public byte getOp() { + return this.op; + } + + /** + * @return hardware address type. + */ + public byte getHtype() { + return this.htype; + } + + /** + * @return hardware address length. + */ + public byte getHlen() { + return this.hlen; + } + + /** + * @return hops field. + */ + public byte getHops() { + return this.hops; + } + + /** + * @return transaction ID. + */ + public int getXid() { + return this.xid; + } + + /** + * @return seconds elapsed since client began address + * acquisition or renewal process. + */ + public short getSecs() { + return this.secs; + } + + /** + * @return flags field. + */ + public short getFlags() { + return this.flags; + } + + /** + * @return client IP address. + */ + public byte[] getCiaddr() { + return this.ciaddr; + } + + /** + * @return 'your' (client) IP address. + */ + public byte[] getYiaddr() { + return this.yiaddr; + } + + /** + * @return address of next server to use in bootstrap. + */ + public byte[] getSiaddr() { + return this.siaddr; + } + + /** + * @return relay agent IP address. + */ + public byte[] getGiaddr() { + return this.giaddr; + } + + /** + * @return client harware address. + */ + public byte[] getChaddr() { + return this.chaddr; + } + + /** + * @return optional server host name. + */ + public byte[] getSname() { + return this.sname; + } + + /** + * @return boot file name. + */ + public byte[] getFile() { + return this.file; + } + + /** + * @return a byte array containing options + */ + public byte[] getOptions() { + if (this.optionsList == null) { + initialize(); + } + return this.optionsList.externalize(); + } + + /** + * @return An interger representation of the message + * destination port + */ + public int getPort() { + return this.gPort; + } + + /** + * Get message destination hostname + * + * @return A string representing the hostname of the + * message destination server + */ + public String getDestinationAddress() { + return this.destination_IP.getHostAddress(); + } + + /** + * Sets DHCP options in DHCPMessage. If option already exists + * then remove old option and insert a new one. + * + * @param inOptNum option number + * @param inOptionData option data + */ + public void setOption(int inOptNum, byte[] inOptionData) { + this.optionsList.setOption((byte) inOptNum, inOptionData); + } + + /** + * Returns specified DHCP option that matches the input code. Null is + * returned if option is not set. + * + * @param inOptNum option number + * + * @return the option matching input code + */ + public byte[] getOption(int inOptNum) { + if (this.optionsList == null) { + initialize(); + } + return this.optionsList.getOption((byte) inOptNum); + } + + /** + * Removes the specified DHCP option that matches the input code. + * + * @param inOptNum option number + */ + public void removeOption(int inOptNum) { + if (this.optionsList == null) { + initialize(); + } + this.optionsList.removeOption((byte) inOptNum); + } + + /** + * Report whether or not the input option is set. + * + * @param inOptNum option number + * + * @return is the given option set? + */ + public boolean IsOptSet(int inOptNum) { + if (this.optionsList == null) { + initialize(); + } + + return this.optionsList.contains((byte) inOptNum); + } +} diff --git a/src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPOptions.java b/src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPOptions.java new file mode 100644 index 0000000..1a07efb --- /dev/null +++ b/src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPOptions.java @@ -0,0 +1,235 @@ +package com.btr.proxy.search.wpad.dhcp; + +import java.util.Enumeration; +import java.util.Hashtable; + +/** + * This class represents a linked list of options for a DHCP message. + * Its purpose is to ease option handling such as add, remove or change. + * + * @author Jason Goldschmidt and Simon Frankenberger + */ +public class DHCPOptions { + public static final int OPTION_PAD = 0; + public static final int OPTION_NETMASK = 1; + public static final int OPTION_TIME_OFFSET = 2; + public static final int OPTION_ROUTERS = 3; + public static final int OPTION_TIME_SERVERS = 4; + public static final int OPTION_NAME_SERVERS = 5; + public static final int OPTION_DNS_SERVERS = 6; + public static final int OPTION_LOG_SERVERS = 7; + public static final int OPTION_COOKIE_SERVERS = 8; + public static final int OPTION_LPR_SERVERS = 9; + public static final int OPTION_IMPRESS_SERVERS = 10; + public static final int OPTION_RESSOURCE_LOCATION_SERVERS = 11; + public static final int OPTION_HOSTNAME = 12; + public static final int OPTION_BOOT_FILESIZE = 13; + public static final int OPTION_MERIT_DUMPFILE = 14; + public static final int OPTION_DOMAIN_NAME = 15; + public static final int OPTION_SWAP_SERVER = 16; + public static final int OPTION_ROOT_PATH = 17; + public static final int OPTION_EXTENSIONS_PATH = 18; + public static final int OPTION_END = 255; + + public static final int OPTION_IP_HOST_FORWARDING_ENABLE = 19; + public static final int OPTION_IP_HOST_NON_LOCAL_SOURCE_ROUTING_ENABLE = 20; + public static final int OPTION_IP_HOST_POLICY_FILTERS = 21; + public static final int OPTION_IP_HOST_MAXIMUM_DATAGRAM_REASSEMBLY_SIZE = 22; + public static final int OPTION_IP_HOST_DEFAULT_TTL = 23; + public static final int OPTION_IP_HOST_MTU_AGEING_TIMEOUT = 24; + public static final int OPTION_IP_HOST_MTU_PLATEAU_TABLE = 25; + + public static final int OPTION_IP_INTERFACE_MTU = 26; + public static final int OPTION_IP_INTERFACE_ALL_SUBNETS_LOCAL_ENABLE = 27; + public static final int OPTION_IP_INTERFACE_BROADCAST_ADDRESS = 28; + public static final int OPTION_IP_INTERFACE_PERFORM_MASK_DISCOVERY_ENABLE = 29; + public static final int OPTION_IP_INTERFACE_MASK_SUPPLIER_ENABLE = 30; + public static final int OPTION_IP_INTERFACE_PERFORM_ROUTER_DISCOVERY_ENABLE = 31; + public static final int OPTION_IP_INTERFACE_ROUTER_SOLICITATION_ADDRESS = 32; + public static final int OPTION_IP_INTERFACE_STATIC_ROUTES = 33; + + public static final int OPTION_LINK_TRAILER_ENCAPSULATION_ENABLE = 34; + public static final int OPTION_LINK_ARP_CACHE_TIMEOUT = 35; + public static final int OPTION_LINK_ETHERNET_ENCAPSULATION_ENABLE = 36; + + public static final int OPTION_TCP_DEFAULT_TTL = 37; + public static final int OPTION_TCP_KEEP_ALIVE_INTERVAL = 38; + public static final int OPTION_TCP_KEEP_ALIVE_GERBAGE_ENABLE = 39; + + public static final int OPTION_NIS_DOMAIN = 40; + public static final int OPTION_NIS_SERVERS = 41; + public static final int OPTION_NTP_SERVERS = 42; + + public static final int OPTION_SERVICE_VENDOR_SPECIFIC_INFORMATIONS = 43; + public static final int OPTION_SERVICE_NETBOIS_NAME_SERVERS = 44; + public static final int OPTION_SERVICE_NETBOIS_DATAGRAM_DISTRIBUTION_SERVERS = 45; + public static final int OPTION_SERVICE_NETBOIS_NODE_TYPE = 46; + public static final int OPTION_SERVICE_NETBOIS_SCOPE_TYPE = 47; + public static final int OPTION_SERVICE_X_FONT_SERVERS = 48; + public static final int OPTION_SERVICE_X_DISPLAY_MANAGERS = 49; + + public static final int OPTION_DHCP_IP_ADRESS_REQUESTED = 50; + public static final int OPTION_DHCP_IP_LEASE_TIME = 51; + public static final int OPTION_DHCP_OVERLOAD = 52; + public static final int OPTION_DHCP_MESSAGE_TYPE = 53; + public static final int OPTION_DHCP_SERVER_IDENTIFIER = 54; + public static final int OPTION_DHCP_PARAMETER_REQUEST_LIST = 55; + public static final int OPTION_DHCP_MESSAGE = 56; + public static final int OPTION_DHCP_MAXIMUM_MESSAGE_SIZE = 57; + public static final int OPTION_DHCP_RENEWAL_TIME = 58; + public static final int OPTION_DHCP_REBIND_TIME = 59; + public static final int OPTION_DHCP_CLASS_IDENTIFIER = 60; + public static final int OPTION_DHCP_CLIENT_IDENTIFIER = 61; + + + /** + *This inner class represent an entry in the Option Table + */ + + class DHCPOptionsEntry { + protected byte code; + protected byte length; + protected byte content[]; + + public DHCPOptionsEntry(byte entryCode, byte entryLength, + byte entryContent[]) { + this.code = entryCode; + this.length = entryLength; + this.content = entryContent; + } + + @Override + public String toString() { + return "Code: " + this.code + "\nContent: " + new String(this.content); + } + } + + private Hashtable<Byte, DHCPOptionsEntry> optionsTable = null; + + public DHCPOptions() { + this.optionsTable = new Hashtable<Byte, DHCPOptionsEntry>(); + } + + /** + * Removes option with specified bytecode + * @param entryCode The code of option to be removed + */ + + public void removeOption(byte entryCode) { + this.optionsTable.remove(new Byte(entryCode)); + } + + /** + * Returns true if option code is set in list; false otherwise + * @param entryCode The node's option code + * @return true if option is set, otherwise false + */ + public boolean contains(byte entryCode) { + return this.optionsTable.containsKey(new Byte(entryCode)); + } + + /** + * Determines if list is empty + * @return true if there are no options set, otherwise false + */ + public boolean isEmpty() { + return this.optionsTable.isEmpty(); + } + + /** + * Fetches value of option by its option code + * @param entryCode The node's option code + * @return byte array containing the value of option entryCode. + * null is returned if option is not set. + */ + public byte[] getOption(byte entryCode) { + if (this.contains(entryCode)) { + DHCPOptionsEntry ent = this.optionsTable.get(new Byte(entryCode)); + return ent.content; + } + else { + return null; + } + } + + /** + * Changes an existing option to new value + * @param entryCode The node's option code + * @param value Content of node option + */ + public void setOption(byte entryCode, byte value[]) { + DHCPOptionsEntry opt = new DHCPOptionsEntry(entryCode, (byte) value.length, value); + this.optionsTable.put(new Byte(entryCode), opt); + } + + /** + * Returns the option value of a specified option code in a byte array + * @param length Length of option content + * @param position Location in array of option node + * @param options The byte array of options + * @return byte array containing the value for the option + */ + private byte[] getArrayOption(int length, int position, byte options[]) { + byte value[] = new byte[length]; + for (int i = 0; i < length; i++) { + value[i] = options[position + i]; + } + return value; + } + + /** + * Converts an options byte array to a linked list + * @param optionsArray The byte array representation of the options list + */ + public void internalize(byte[] optionsArray) { + + /* Assume options valid and correct */ + int pos = 4; // ignore vendor magic cookie + byte code, length; + byte value[]; + + while (optionsArray[pos] != (byte) 255) { // until end option + code = optionsArray[pos++]; + length = optionsArray[pos++]; + value = getArrayOption(length, pos, optionsArray); + setOption(code, value); + pos += length; // increment position pointer + } + } + + /** + * Converts a linked options list to a byte array + * @return array representation of optionsTable + */ + // todo provide overflow return + public byte[] externalize() { + byte[] options = new byte[312]; + + options[0] = (byte) 99; // insert vendor magic cookie + options[1] = (byte) 130; + options[2] = (byte) 83; + options[3] = (byte) 99; + + int position = 4; + Enumeration<DHCPOptionsEntry> e = this.optionsTable.elements(); + + while (e.hasMoreElements()) { + DHCPOptionsEntry entry = e.nextElement(); + options[position++] = entry.code; + options[position++] = entry.length; + for (int i = 0; i < entry.length; ++i) { + options[position++] = entry.content[i]; + } + } + + options[position] = (byte) 255; // insert end option + return options; + } + + /** + * Prints the options linked list: For testing only. + */ + public void printList() { + System.out.println(this.optionsTable.toString()); + } +} diff --git a/src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPSocket.java b/src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPSocket.java new file mode 100644 index 0000000..6dbe2bf --- /dev/null +++ b/src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPSocket.java @@ -0,0 +1,107 @@ +package com.btr.proxy.search.wpad.dhcp; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketException; +import java.net.UnknownHostException; + +/** + * This class represents a Socket for sending DHCP Messages + * + * @author Jason Goldschmidt and Simon Frankenberger + * + * @see java.net.DatagramSocket + */ + +public class DHCPSocket extends DatagramSocket { + /** + * Default socket timeout (1 second) + */ + private int SOCKET_TIMEOUT = 5000; + + /** + * Default MTU (Maximum Transmission Unit) for ethernet (in bytes) + */ + private int mtu = 1500; + + /** + * Constructor for creating DHCPSocket on a specific port on the local + * machine. + * + * @param inPort The port for the application to bind. + * + * @throws SocketException As thrown by the {@link Socket} constructor + */ + public DHCPSocket(int inPort) throws SocketException { + super(inPort); + setSoTimeout(this.SOCKET_TIMEOUT); + } + + /** + * Sets the Maximum Transfer Unit for the UDP DHCP Packets to be set. + * + * @param inSize Integer representing desired MTU + */ + public void setMTU(int inSize) { + this.mtu = inSize; + } + + /** + * Returns the set MTU for this socket + * + * @return The Maximum Transfer Unit set for this socket + */ + public int getMTU() { + return this.mtu; + } + + /** + * Sends a DHCPMessage object to a predifined host. + * + * @param inMessage Well-formed DHCPMessage to be sent to a server + * + * @throws IOException If the message could not be sent. + */ + public synchronized void send(DHCPMessage inMessage) throws IOException { + byte data[] = new byte[this.mtu]; + data = inMessage.externalize(); + InetAddress dest = null; + try { + dest = InetAddress.getByName(inMessage.getDestinationAddress()); + } + catch (UnknownHostException e) { + } + + DatagramPacket outgoing = new DatagramPacket(data, data.length, dest, + inMessage.getPort()); + + send(outgoing); // send outgoing message + } + + /** + * Receives a datagram packet containing a DHCP Message into + * a DHCPMessage object. + * + * @return <code>true</code> if message is received, + * <code>false</code> if timeout occurs. + * @param outMessage DHCPMessage object to receive new message into + */ + public synchronized boolean receive(DHCPMessage outMessage) { + try { + DatagramPacket incoming = new DatagramPacket(new byte[this.mtu], + this.mtu); + //gSocket. + receive(incoming); // block on receive for SOCKET_TIMEOUT + + outMessage.internalize(incoming.getData()); + } + catch (java.io.IOException e) { + e.printStackTrace(); + return false; + } // end catch + return true; + } +} |