/*
* This file is part of dhcp4java, a DHCP API for the Java language.
* (c) 2006 Stephan Hadinger
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.dhcp4java;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.net.DatagramPacket;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.dhcp4java.DHCPConstants.*;
/**
* The basic class for manipulating DHCP packets.
*
* @author Stephan Hadinger
* @version 1.00
*
* <p>There are two basic ways to build a new DHCPPacket object.
* <p>First one is to build an object from scratch using the constructor and setters.
* If you need to set repeatedly the same set of parameters and options,
* you can create a "master" object and clone it many times.
*
* <pre>
* DHCPPacket discover = new DHCPPacket();
* discover.setOp(DHCPPacket.BOOTREQUEST);
* discover.setHtype(DHCPPacket.HTYPE_ETHER);
* discover.setHlen((byte) 6);
* discover.setHops((byte) 0);
* discover.setXid( (new Random()).nextInt() );
* ...
* </pre>
* Second is to decode a DHCP datagram received from the network.
* In this case, the object is created through a factory.
*
* <p>Example: simple DHCP sniffer
* <pre>
* DatagramSocket socket = new DatagramSocket(67);
* while (true) {
* DatagramPacket pac = new DatagramPacket(new byte[1500], 1500);
* socket.receive(pac);
* DHCPPacket dhcp = DHCPPacket.getPacket(pac);
* System.out.println(dhcp.toString());
* }
* </pre>
* In this second way, beware that a <tt>BadPacketExpcetion</tt> is thrown
* if the datagram contains invalid DHCP data.
*
*
* <p><b>Getters and Setters</b>: methods are provided with high-level data structures
* wherever it is possible (String, InetAddress...). However there are also low-overhead
* version (suffix <tt>Raw</tt>) dealing directly with <tt>byte[]</tt> for maximum performance.
* They are useful in servers for copying parameters in a servers from a request to a response without
* any type conversion. All parameters are copies, you may modify them as you like without
* any side-effect on the <tt>DHCPPacket</tt> object.
*
* <h4>DHCP datagram format description:</h4>
* <blockquote><table cellspacing=2>
* <tr><th>Field</th><th>Octets</th><th>Description</th></tr>
* <tr><td valign=top><tt>op</tt></td><td valign=top>1</td>
* <td>Message op code / message type.<br>
* use constants
* <tt>BOOTREQUEST</tt>,
* <tt>BOOTREPLY</tt></td></tr>
* <tr><td valign=top><tt>htype</tt></td>
* <td valign=top>1</td><td>Hardware address type, see ARP section in
* "Assigned Numbers" RFC<br>
* use constants
* <tt>HTYPE_ETHER</tt>,
* <tt>HTYPE_IEEE802</tt>,
* <tt>HTYPE_FDDI</tt></td></tr>
* <tr><td valign=top><tt>hlen</tt></td><td>1</td><td>Hardware address length
* (e.g. '6' for ethernet).</td></tr>
* <tr><td valign=top><tt>hops</tt></td><td valign=top>1</td><td>Client sets to zero, optionally used
* by relay agents when booting via a relay agent.</td></tr>
* <tr><td valign=top><tt>xid</tt></td><td valign=top>4</td>
* <td>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.</td></tr>
* <tr><td valign=top><tt>secs</tt></td><td valign=top>2</td>
* <td>Filled in by client, seconds elapsed since client
* began address acquisition or renewal process.</td></tr>
* <tr><td valign=top><tt>flags</tt></td><td valign=top>2</td>
* <td>Flags (see below).</td></tr>
* <tr><td valign=top><tt>ciaddr</tt></td><td valign=top>4</td>
* <td>Client IP address; only filled in if client is in
* BOUND, RENEW or REBINDING state and can respond
* to ARP requests.</td></tr>
* <tr><td valign=top><tt>yiaddr</tt></td><td valign=top>4</td>
* <td>'your' (client) IP address.</td></tr>
* <tr><td valign=top><tt>siaddr</tt></td><td valign=top>4</td>
* <td>IP address of next server to use in bootstrap;
* returned in DHCPOFFER, DHCPACK by server.</td></tr>
* <tr><td valign=top><tt>giaddr</tt></td><td valign=top>4</td>
* <td>Relay agent IP address, used in booting via a
* relay agent.</td></tr>
* <tr><td valign=top><tt>chaddr</tt></td><td valign=top>16</td>
* <td>Client hardware address.</td></tr>
* <tr><td valign=top><tt>sname</tt></td><td valign=top>64</td>
* <td>Optional server host name, null terminated string.</td></tr>
* <tr><td valign=top><tt>file</tt></td><td valign=top>128</td>
* <td>Boot file name, null terminated string; "generic"
* name or null in DHCPDISCOVER, fully qualified
* directory-path name in DHCPOFFER.</td></tr>
* <tr><td valign=top><tt>isDhcp</tt></td><td valign=top>4</td>
* <td>Controls whether the packet is BOOTP or DHCP.
* DHCP contains the "magic cookie" of 4 bytes.
* 0x63 0x82 0x53 0x63.</td></tr>
* <tr><td valign=top><tt>DHO_*code*</tt></td><td valign=top>*</td>
* <td>Optional parameters field. See the options
* documents for a list of defined options. See below.</td></tr>
* <tr><td valign=top><tt>padding</tt></td><td valign=top>*</td>
* <td>Optional padding at the end of the packet.</td></tr>
* </table></blockquote>
*
* <h4>DHCP Option</h4>
*
* The following options are codes are supported:
* <pre>
* DHO_SUBNET_MASK(1)
* DHO_TIME_OFFSET(2)
* DHO_ROUTERS(3)
* DHO_TIME_SERVERS(4)
* DHO_NAME_SERVERS(5)
* DHO_DOMAIN_NAME_SERVERS(6)
* DHO_LOG_SERVERS(7)
* DHO_COOKIE_SERVERS(8)
* DHO_LPR_SERVERS(9)
* DHO_IMPRESS_SERVERS(10)
* DHO_RESOURCE_LOCATION_SERVERS(11)
* DHO_HOST_NAME(12)
* DHO_BOOT_SIZE(13)
* DHO_MERIT_DUMP(14)
* DHO_DOMAIN_NAME(15)
* DHO_SWAP_SERVER(16)
* DHO_ROOT_PATH(17)
* DHO_EXTENSIONS_PATH(18)
* DHO_IP_FORWARDING(19)
* DHO_NON_LOCAL_SOURCE_ROUTING(20)
* DHO_POLICY_FILTER(21)
* DHO_MAX_DGRAM_REASSEMBLY(22)
* DHO_DEFAULT_IP_TTL(23)
* DHO_PATH_MTU_AGING_TIMEOUT(24)
* DHO_PATH_MTU_PLATEAU_TABLE(25)
* DHO_INTERFACE_MTU(26)
* DHO_ALL_SUBNETS_LOCAL(27)
* DHO_BROADCAST_ADDRESS(28)
* DHO_PERFORM_MASK_DISCOVERY(29)
* DHO_MASK_SUPPLIER(30)
* DHO_ROUTER_DISCOVERY(31)
* DHO_ROUTER_SOLICITATION_ADDRESS(32)
* DHO_STATIC_ROUTES(33)
* DHO_TRAILER_ENCAPSULATION(34)
* DHO_ARP_CACHE_TIMEOUT(35)
* DHO_IEEE802_3_ENCAPSULATION(36)
* DHO_DEFAULT_TCP_TTL(37)
* DHO_TCP_KEEPALIVE_INTERVAL(38)
* DHO_TCP_KEEPALIVE_GARBAGE(39)
* DHO_NIS_SERVERS(41)
* DHO_NTP_SERVERS(42)
* DHO_VENDOR_ENCAPSULATED_OPTIONS(43)
* DHO_NETBIOS_NAME_SERVERS(44)
* DHO_NETBIOS_DD_SERVER(45)
* DHO_NETBIOS_NODE_TYPE(46)