⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dhcppacket.java

📁 DHCP 的JAVA实现
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
/*
 *	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)
 * DHO_NETBIOS_SCOPE(47)
 * DHO_FONT_SERVERS(48)
 * DHO_X_DISPLAY_MANAGER(49)
 * DHO_DHCP_REQUESTED_ADDRESS(50)
 * DHO_DHCP_LEASE_TIME(51)
 * DHO_DHCP_OPTION_OVERLOAD(52)
 * DHO_DHCP_MESSAGE_TYPE(53)
 * DHO_DHCP_SERVER_IDENTIFIER(54)
 * DHO_DHCP_PARAMETER_REQUEST_LIST(55)
 * DHO_DHCP_MESSAGE(56)
 * DHO_DHCP_MAX_MESSAGE_SIZE(57)
 * DHO_DHCP_RENEWAL_TIME(58)
 * DHO_DHCP_REBINDING_TIME(59)
 * DHO_VENDOR_CLASS_IDENTIFIER(60)
 * DHO_DHCP_CLIENT_IDENTIFIER(61)
 * DHO_NWIP_DOMAIN_NAME(62)
 * DHO_NWIP_SUBOPTIONS(63)
 * DHO_NIS_DOMAIN(64)
 * DHO_NIS_SERVER(65)
 * DHO_TFTP_SERVER(66)
 * DHO_BOOTFILE(67)
 * DHO_MOBILE_IP_HOME_AGENT(68)
 * DHO_SMTP_SERVER(69)
 * DHO_POP3_SERVER(70)
 * DHO_NNTP_SERVER(71)
 * DHO_WWW_SERVER(72)
 * DHO_FINGER_SERVER(73)
 * DHO_IRC_SERVER(74)
 * DHO_STREETTALK_SERVER(75)
 * DHO_STDA_SERVER(76)
 * DHO_USER_CLASS(77)
 * DHO_FQDN(81)
 * DHO_DHCP_AGENT_OPTIONS(82)
 * DHO_NDS_SERVERS(85)
 * DHO_NDS_TREE_NAME(86)
 * DHO_USER_AUTHENTICATION_PROTOCOL(98)
 * DHO_AUTO_CONFIGURE(116)
 * DHO_NAME_SERVICE_SEARCH(117)
 * DHO_SUBNET_SELECTION(118)
 * </pre>
 * 
 * <p>These options can be set and get through basic low-level <tt>getOptionRaw</tt> and
 * <tt>setOptionRaw</tt> passing <tt>byte[]</tt> structures. Using these functions, data formats
 * are under your responsibility. Arrays are always passed by copies (clones) so you can modify
 * them freely without side-effects. These functions allow maximum performance, especially
 * when copying options from a request datagram to a response datagram.
 * 
 * <h4>Special case: DHO_DHCP_MESSAGE_TYPE</h4>
 * The DHCP Message Type (option 53) is supported for the following values
 * <pre>
 * DHCPDISCOVER(1)
 * DHCPOFFER(2)
 * DHCPREQUEST(3)
 * DHCPDECLINE(4)
 * DHCPACK(5)
 * DHCPNAK(6)
 * DHCPRELEASE(7)
 * DHCPINFORM(8)
 * DHCPFORCERENEW(9)
 * DHCPLEASEQUERY(13)
 * </pre>
 * 
 * <h4>DHCP option formats</h4>
 * 
 * A limited set of higher level data-structures are supported. Type checking is enforced
 * according to rfc 2132. Check corresponding methods for a list of option codes allowed for
 * each datatype.
 * 
 * <blockquote>
 * <br>Inet (4 bytes - IPv4 address)
 * <br>Inets (X*4 bytes - list of IPv4 addresses)
 * <br>Short (2 bytes - short)
 * <br>Shorts (X*2 bytes - list of shorts)
 * <br>Byte (1 byte)
 * <br>Bytes (X bytes - list of 1 byte parameters)
 * <br>String (X bytes - ASCII string)
 * <br>
 * </blockquote>
 * 
 * 
 * <p><b>Note</b>: this class is not synchronized for maximum performance.
 * However, it is unlikely that the same <tt>DHCPPacket</tt> is used in two different 
 * threads in real life DHPC servers or clients. Multi-threading acces
 * to an instance of this class is at your own risk.
 * 
 * <p><b>Limitations</b>: this class doesn't support spanned options or options longer than 256 bytes.
 * It does not support options stored in <tt>sname</tt> or <tt>file</tt> fields.
 * 
 * <p>This API is originally a port from my PERL
 * <tt><a href="http://search.cpan.org/~shadinger/">Net::DHCP</a></tt> api.
 * 
 * <p><b>Future extensions</b>: IPv6 support, extended data structure TODO...
 * 
 */
public class DHCPPacket implements Cloneable, Serializable {
	private static final long   serialVersionUID = 1L;

    private static final Logger logger = Logger.getLogger(DHCPPacket.class.getName().toLowerCase());
    
    // ----------------------------------------------------------------------
    // user defined comment
    private String  comment;   // Free user-defined comment

    // ----------------------------------------------------------------------
    // static structure of the packet
    private byte    op;        // Op code
    private byte    htype;     // HW address Type
    private byte    hlen;      // hardware address length
    private byte    hops;      // Hw options
    private int     xid;       // transaction id
    private short   secs;      // elapsed time from trying to boot
    private short   flags;     // flags
    private byte[]  ciaddr;    // client IP
    private byte[]  yiaddr;    // your client IP
    private byte[]  siaddr;    // Server IP
    private byte[]  giaddr;    // relay agent IP
    private byte[]  chaddr;    // Client HW address
    private byte[]  sname;     // Optional server host name
    private byte[]  file;      // Boot file name
    
    // ----------------------------------------------------------------------
    // options part of the packet

    // DHCP options
    // Invariant 1: K is identical to V.getCode()
    // Invariant 2: V.value is never <tt>null</tt>
    // Invariant 3; K is not 0 (PAD) and not -1 (END)
    private Map<Byte, DHCPOption> options;
    private boolean               isDhcp;    // well-formed DHCP Packet ?
    private boolean               truncated; // are the option truncated
    // ----------------------------------------------------------------------
    // extra bytes for padding
    private byte[]      padding;	// end of packet padding
    
    // ----------------------------------------------------------------------
    // Address/port address of the machine, which this datagram is being sent to
    // or received from.
    private InetAddress address;
    private int         port;
    
    
    /**
     * Constructor for the <tt>DHCPPacket</tt> class.
     *
     * <p>This creates an empty <tt>DHCPPacket</tt> datagram.
     * All data is default values and the packet is still lacking key data
     * to be sent on the wire.
     */
    public DHCPPacket() {
        this.comment = "";
        this.op      = BOOTREPLY;
        this.htype   = HTYPE_ETHER;
        this.hlen    = 6;
        this.ciaddr  = new byte[  4];
        this.yiaddr  = new byte[  4];
        this.siaddr  = new byte[  4];
        this.giaddr  = new byte[  4];
        this.chaddr  = new byte[ 16];
        this.sname   = new byte[ 64];
        this.file    = new byte[128];
        this.padding = new byte[0];
        this.isDhcp  = true;
        this.options = new LinkedHashMap<Byte, DHCPOption>();
    }

    /**
     * Factory for creating <tt>DHCPPacket</tt> objects by parsing a
     * <tt>DatagramPacket</tt> object.
     *
     * @param datagram the UDP datagram received to be parsed
     * @return the newly create <tt>DHCPPacket</tt> instance
     * @throws DHCPBadPacketException the datagram is malformed and cannot be parsed properly.
     * @throws IllegalArgumentException datagram is <tt>null</tt>
     * @throws IOException
     */
    public static DHCPPacket getPacket(DatagramPacket datagram) throws DHCPBadPacketException {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -