summaryrefslogtreecommitdiffstats
path: root/src/main/java/com/btr/proxy/search/wpad/dhcp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/btr/proxy/search/wpad/dhcp')
-rw-r--r--src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPMessage.java880
-rw-r--r--src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPOptions.java235
-rw-r--r--src/main/java/com/btr/proxy/search/wpad/dhcp/DHCPSocket.java107
3 files changed, 1222 insertions, 0 deletions
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;
+ }
+}