Overview
The Dynamic Host Configuration Protocol (DHCP) automates the assignment of IP addresses and network configuration parameters to devices on a network. DHCP eliminates manual configuration requirements by establishing a client-server architecture where network devices request and receive configuration data dynamically.
DHCP operates at the application layer of the TCP/IP model, using UDP ports 67 (server) and 68 (client). The protocol evolved from BOOTP (Bootstrap Protocol) and became standardized through RFC 2131 in 1997, with subsequent RFCs adding functionality like option codes and failover mechanisms.
The protocol serves critical infrastructure roles in modern networks. Without DHCP, administrators would manually configure each device with unique IP addresses, subnet masks, gateway addresses, and DNS server information. This manual process becomes impractical in networks with hundreds or thousands of devices, especially when considering mobile devices that move between networks.
DHCP handles four primary configuration parameters: IP address assignment, subnet mask definition, default gateway specification, and DNS server identification. Additional parameters include NTP servers, domain names, and vendor-specific options through a flexible option system that supports over 250 different configuration parameters.
# Basic DHCP lease information structure
lease = {
ip_address: '192.168.1.100',
subnet_mask: '255.255.255.0',
router: '192.168.1.1',
dns_servers: ['8.8.8.8', '8.8.4.4'],
lease_time: 86400,
renewal_time: 43200,
rebinding_time: 75600
}
The protocol distinguishes between three allocation mechanisms: dynamic allocation assigns IP addresses with finite lease periods, automatic allocation provides permanent address assignments, and manual allocation binds specific MAC addresses to predetermined IP addresses.
Key Principles
DHCP operates through a four-phase handshake known as DORA: Discovery, Offer, Request, and Acknowledgment. Each phase serves specific purposes in establishing network configuration.
Discovery Phase: The client broadcasts a DHCPDISCOVER message to locate available DHCP servers. This broadcast uses the destination IP 255.255.255.255 since the client lacks network configuration. The message includes the client's MAC address and may include requested parameters or previous IP address information.
Offer Phase: DHCP servers receiving the discovery respond with DHCPOFFER messages containing proposed IP addresses and configuration parameters. Multiple servers may respond, creating a competitive offer scenario. The offer includes the proposed IP address, lease duration, and server identifier.
Request Phase: The client selects one offer and broadcasts a DHCPREQUEST message indicating acceptance. This broadcast notifies all servers of the selection, allowing rejected servers to reclaim offered addresses. The request includes the selected server identifier and requested IP address.
Acknowledgment Phase: The selected server responds with a DHCPACK message confirming the lease and providing complete configuration data. If the server cannot fulfill the request, it sends DHCPNAK, forcing the client to restart the discovery process.
# DHCP message types as constants
module DHCPMessageType
DISCOVER = 1
OFFER = 2
REQUEST = 3
DECLINE = 4
ACK = 5
NAK = 6
RELEASE = 7
INFORM = 8
end
Lease management extends beyond initial configuration. DHCP implements a three-timer system controlling lease lifecycle: T1 (renewal timer), T2 (rebinding timer), and lease expiration. At T1 (typically 50% of lease duration), the client attempts unicast renewal with the original server. If renewal fails by T2 (typically 87.5% of lease duration), the client broadcasts renewal requests to any available server. Lease expiration forces the client to release the address and restart discovery.
The protocol maintains state through lease databases on both client and server. Clients track current leases, attempting to renew previous addresses on network reconnection. Servers maintain address pools, allocated addresses, and lease timing information. This state management enables consistent addressing for devices while allowing address reuse when leases expire.
DHCP packets contain fixed-format headers and variable-length options. The fixed portion includes operation code, hardware type, hardware address length, transaction ID, elapsed time, flags, client IP address, offered IP address, server IP address, gateway IP address, client hardware address, and server hostname fields. Options follow the fixed header, using a tag-length-value encoding scheme.
Option 53 identifies the message type (DISCOVER, OFFER, REQUEST, ACK, NAK, RELEASE, DECLINE, INFORM). Option 51 specifies requested lease time. Option 50 requests specific IP addresses. Option 54 identifies the server. These options enable the flexible, extensible communication required for diverse network environments.
Relay agents extend DHCP across network boundaries. When clients and servers reside on different subnets, routers acting as relay agents intercept broadcast DHCPDISCOVER messages, encapsulate them in unicast packets, and forward them to configured DHCP servers. The relay agent field in DHCP packets stores the original gateway address, allowing servers to assign addresses from appropriate subnets.
Implementation Approaches
DHCP implementations divide into client-side and server-side components, each with distinct architectural considerations.
Centralized Server Architecture: Traditional DHCP deployments use centralized servers managing address pools for multiple subnets through relay agents. This approach concentrates configuration management, simplifying policy enforcement and monitoring. Centralized servers handle high client volumes efficiently but introduce single points of failure unless paired with failover mechanisms.
# Centralized server configuration representation
class DHCPServerConfig
attr_accessor :subnets, :global_options, :failover_peer
def initialize
@subnets = []
@global_options = {}
@failover_peer = nil
end
def add_subnet(network, netmask, range_start, range_end, options = {})
@subnets << {
network: network,
netmask: netmask,
pool: {
range: [range_start, range_end],
options: options
}
}
end
end
config = DHCPServerConfig.new
config.add_subnet(
'192.168.1.0',
'255.255.255.0',
'192.168.1.100',
'192.168.1.200',
{ router: '192.168.1.1', dns: ['8.8.8.8', '8.8.4.4'] }
)
Distributed Server Architecture: Large networks deploy multiple DHCP servers, each authoritative for specific subnets. Distribution reduces broadcast traffic and improves fault tolerance through geographic separation. Coordination between servers prevents address conflicts, though this requires careful subnet boundary definition and monitoring.
Failover Implementation: DHCP failover protocols enable redundant server pairs sharing address pool state. Primary and secondary servers communicate continuously, synchronizing lease information. When the primary fails, the secondary assumes responsibility without client disruption. Failover implementations use split-scope (each server manages distinct address ranges) or shared-scope (servers share the complete pool with state synchronization) models.
Client implementations vary by operating system and use case. Full-featured clients manage lease lifecycle automatically, handling renewal, rebinding, and release operations. Minimal clients perform only initial address acquisition, suited for embedded systems or constrained environments. The client implementation must handle network interface changes, sleep/wake cycles, and network transitions.
Stateless vs Stateful Operation: DHCPv6 introduces stateless operation where clients obtain configuration parameters without address assignment, using IPv6 stateless address autoconfiguration (SLAAC) for addressing. This hybrid approach combines DHCP's configuration distribution with SLAAC's decentralized addressing. Stateful DHCPv6 mimics traditional DHCP, assigning addresses and configuration parameters.
Address Pool Management: Servers implement various pool management strategies. Sequential allocation assigns addresses in order, simplifying lease tracking. Random allocation distributes addresses across the pool, reducing address pattern predictability. Sticky allocation attempts to reassign previous addresses to returning clients, supporting address-based access controls.
Ruby Implementation
Ruby provides libraries for both DHCP client and server functionality, though production DHCP services typically use dedicated implementations like ISC DHCP or dnsmasq.
The dhcp gem offers basic DHCP message parsing and construction capabilities. This gem handles packet encoding/decoding but leaves protocol flow management to the application.
require 'dhcp'
# Create a DHCP DISCOVER message
discover = DHCP::Message.new
discover.op = DHCP::OP_BOOTREQUEST
discover.htype = DHCP::HTYPE_ETHER
discover.hlen = 6
discover.xid = rand(0xFFFFFFFF)
discover.chaddr = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55]
discover.options << DHCP::MessageTypeOption.new(DHCP::DISCOVER)
discover.options << DHCP::ParameterRequestListOption.new([1, 3, 6, 15])
# Serialize to UDP payload
packet = discover.pack
Creating a DHCP client requires managing UDP sockets, broadcast permissions, and message timing. The client must bind to port 68 and enable broadcast socket options.
require 'socket'
class SimpleDHCPClient
def initialize(interface)
@interface = interface
@mac_address = get_mac_address(interface)
@socket = UDPSocket.new
@socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
@socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
@socket.bind('0.0.0.0', 68)
end
def discover
message = build_discover_message
@socket.send(message, 0, '255.255.255.255', 67)
# Wait for OFFER with timeout
ready = IO.select([@socket], nil, nil, 10)
return nil unless ready
response, = @socket.recvfrom(1500)
parse_offer(response)
end
def request(offer)
message = build_request_message(offer)
@socket.send(message, 0, '255.255.255.255', 67)
ready = IO.select([@socket], nil, nil, 10)
return nil unless ready
response, = @socket.recvfrom(1500)
parse_ack(response)
end
private
def build_discover_message
# Construct DHCP DISCOVER packet
# Returns binary packet data
end
def get_mac_address(interface)
# Retrieve interface MAC address
# Platform-specific implementation
end
end
Server implementations require address pool management, lease tracking, and concurrent client handling. The server binds to port 67 and processes incoming requests based on message type.
class DHCPServer
def initialize(config)
@config = config
@leases = {}
@socket = UDPSocket.new
@socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
@socket.bind('0.0.0.0', 67)
end
def run
loop do
data, client_info = @socket.recvfrom(1500)
Thread.new { handle_message(data, client_info) }
end
end
private
def handle_message(data, client_info)
message = parse_dhcp_message(data)
case message.message_type
when DHCP::DISCOVER
handle_discover(message, client_info)
when DHCP::REQUEST
handle_request(message, client_info)
when DHCP::RELEASE
handle_release(message)
when DHCP::DECLINE
handle_decline(message)
end
end
def handle_discover(message, client_info)
ip = allocate_address(message.chaddr)
offer = build_offer(message, ip)
send_response(offer, client_info)
end
def handle_request(message, client_info)
if valid_request?(message)
ack = build_ack(message)
record_lease(message.chaddr, message.requested_ip)
send_response(ack, client_info)
else
nak = build_nak(message)
send_response(nak, client_info)
end
end
def allocate_address(mac_address)
# Check for existing lease
return @leases[mac_address][:ip] if @leases[mac_address]
# Find available address from pool
@config.subnets.each do |subnet|
available = find_available_ip(subnet)
return available if available
end
nil
end
end
The net-dhcp gem provides a higher-level interface for DHCP operations, handling protocol details while exposing simpler APIs.
require 'net/dhcp'
# Parse DHCP packet
packet = Net::DHCP::Packet.parse(raw_data)
puts "Message type: #{packet.message_type}"
puts "Client MAC: #{packet.chaddr}"
puts "Requested IP: #{packet.options[:requested_ip_address]}"
# Build DHCP OFFER
offer = Net::DHCP::Packet.new(
op: Net::DHCP::BOOTREPLY,
xid: packet.xid,
yiaddr: '192.168.1.100',
siaddr: '192.168.1.1',
chaddr: packet.chaddr
)
offer.options[:message_type] = Net::DHCP::OFFER
offer.options[:subnet_mask] = '255.255.255.0'
offer.options[:router] = '192.168.1.1'
offer.options[:dns_servers] = ['8.8.8.8', '8.8.4.4']
offer.options[:lease_time] = 86400
Production Ruby applications typically interact with DHCP servers through system calls or configuration file management rather than implementing protocol logic directly. Management scripts generate DHCP server configurations or query lease databases.
# ISC DHCP configuration generation
class ISCDHCPConfigGenerator
def initialize(subnets)
@subnets = subnets
end
def generate
config = []
config << "default-lease-time 600;"
config << "max-lease-time 7200;"
config << ""
@subnets.each do |subnet|
config << "subnet #{subnet[:network]} netmask #{subnet[:netmask]} {"
config << " range #{subnet[:range_start]} #{subnet[:range_end]};"
config << " option routers #{subnet[:router]};"
config << " option domain-name-servers #{subnet[:dns].join(', ')};"
config << "}"
config << ""
end
config.join("\n")
end
end
Security Implications
DHCP lacks built-in authentication and encryption, creating multiple attack vectors. Understanding these vulnerabilities informs defensive strategies.
Rogue DHCP Servers: Attackers deploy unauthorized DHCP servers responding to client requests with malicious configuration. Clients cannot distinguish legitimate from rogue servers, accepting configuration from the first responder. Rogue servers redirect traffic through attacker-controlled gateways or DNS servers, enabling man-in-the-middle attacks and traffic interception.
DHCP snooping provides partial mitigation. Network switches configured with DHCP snooping designate trusted ports for DHCP server traffic and untrusted ports for client traffic. The switch drops DHCP server messages from untrusted ports, preventing rogue server operation. DHCP snooping builds a binding table mapping MAC addresses to IP addresses, switch ports, and VLANs, enforcing address consistency.
# DHCP snooping binding table entry
class DHCPSnoopingBinding
attr_reader :mac_address, :ip_address, :vlan, :interface, :lease_time
def initialize(mac, ip, vlan, interface)
@mac_address = mac
@ip_address = ip
@vlan = vlan
@interface = interface
@lease_time = Time.now + 86400
end
def expired?
Time.now > @lease_time
end
def validate_packet(source_mac, source_ip, source_port)
return false if expired?
source_mac == @mac_address &&
source_ip == @ip_address &&
source_port == @interface
end
end
DHCP Starvation Attacks: Attackers flood DHCP servers with DISCOVER messages using spoofed MAC addresses, exhausting the address pool. Legitimate clients cannot obtain addresses once the pool depletes. Rate limiting DISCOVER messages and limiting leases per physical port mitigates starvation attacks.
Spoofing and Message Injection: Attackers inject DHCP messages manipulating client configuration or disrupting service. DHCPRELEASE messages with spoofed MAC addresses force lease termination. DHCPNAK messages during renewal force clients to restart discovery. Port security, MAC address filtering, and DHCP snooping limit spoofing opportunities.
Information Disclosure: DHCP traffic reveals network topology, address ranges, DNS servers, and gateway locations. Passive monitoring exposes this information without active attacks. Segmenting networks and using VLANs limits information disclosure scope.
DNS Poisoning via DHCP: Rogue DHCP servers provide malicious DNS server addresses, redirecting domain resolution to attacker-controlled servers. Users receive incorrect IP addresses for legitimate domains, facilitating phishing and credential theft. DNSSEC validation and DNS-over-HTTPS mitigate but don't eliminate this risk.
DHCPv6 introduces authentication through the Authentication option, though deployment remains limited. The Authentication option supports various algorithms including HMAC-MD5, enabling message integrity verification and server authentication.
Secure Implementation Practices: Deploy DHCP servers on dedicated VLANs with strict access controls. Monitor DHCP traffic for anomalies including unexpected servers, unusual request rates, or address pool exhaustion. Implement DHCP snooping on all access switches. Configure short lease times for high-security environments, reducing window for address hijacking. Use static assignments for critical infrastructure.
# DHCP traffic monitoring
class DHCPMonitor
def initialize
@servers_seen = {}
@request_rates = Hash.new { |h, k| h[k] = [] }
end
def analyze_packet(packet)
if packet.message_type == DHCP::OFFER
server_ip = packet.options[:server_identifier]
unless @servers_seen[server_ip]
alert("New DHCP server detected: #{server_ip}")
@servers_seen[server_ip] = Time.now
end
end
if packet.message_type == DHCP::DISCOVER
client_mac = packet.chaddr
@request_rates[client_mac] << Time.now
# Remove requests older than 60 seconds
@request_rates[client_mac].select! { |t| Time.now - t < 60 }
if @request_rates[client_mac].length > 10
alert("Possible DHCP starvation from #{client_mac}")
end
end
end
def alert(message)
# Send alert through monitoring system
puts "SECURITY ALERT: #{message}"
end
end
Tools & Ecosystem
DHCP implementations span open-source servers, commercial solutions, and network infrastructure integrations.
ISC DHCP: The Internet Systems Consortium DHCP server (dhcpd) provides the reference implementation for DHCP on Unix-like systems. ISC DHCP supports DHCPv4 and DHCPv6, failover configurations, dynamic DNS updates, and extensive option support. Configuration uses a declarative format defining global options, subnet declarations, host reservations, and class-based assignments.
ISC DHCP includes dhclient for client functionality and dhcrelay for relay agent operation. The server maintains lease state in dhcpd.leases, recording all active and expired leases with timestamps and identifying information.
dnsmasq: This lightweight server combines DHCP, DNS caching, and router advertisement services. dnsmasq suits small to medium networks, embedded systems, and development environments. Configuration uses a simple key-value format, and the server automatically integrates DHCP and DNS, registering DHCP client hostnames in its DNS cache.
Kea: ISC developed Kea as the modern successor to ISC DHCP. Kea implements a modular architecture with separate processes for DHCPv4, DHCPv6, control agent, and configuration backend. The server stores configuration and leases in databases (MySQL, PostgreSQL, Cassandra), supporting high-availability deployments. Kea exposes RESTful APIs for management and monitoring.
Windows DHCP Server: Microsoft's DHCP server integrates with Active Directory, providing authorization controls and audit logging. The server supports superscopes (groups of scopes), multicast scopes, and policy-based assignment. PowerShell cmdlets enable automation and remote management.
Infoblox and BlueCat: Commercial DDI (DNS, DHCP, IPAM) platforms provide unified management across DNS, DHCP, and IP address management. These systems offer graphical interfaces, reporting, and integration with network automation tools.
dhcpdump: This packet capture analysis tool decodes DHCP traffic, displaying message contents in human-readable format. dhcpdump operates on live captures or pcap files, filtering DHCP-specific traffic from mixed captures.
# Wrapping dhcpdump for Ruby automation
class DHCPPacketAnalyzer
def initialize(interface)
@interface = interface
end
def capture(duration: 60)
cmd = "timeout #{duration} tcpdump -i #{@interface} -w /tmp/dhcp.pcap port 67 or port 68"
system(cmd)
parse_capture('/tmp/dhcp.pcap')
end
def parse_capture(pcap_file)
output = `dhcpdump -i #{pcap_file}`
packets = []
current_packet = nil
output.each_line do |line|
if line =~ /TIME:/
packets << current_packet if current_packet
current_packet = { raw: [] }
end
current_packet[:raw] << line if current_packet
case line
when /DHCP: DISCOVER/
current_packet[:type] = :discover
when /DHCP: OFFER/
current_packet[:type] = :offer
when /YIADDR: ([\d.]+)/
current_packet[:offered_ip] = $1
end
end
packets << current_packet if current_packet
packets
end
end
DHCP Testing Tools: dhcping sends DHCP DISCOVER messages and validates server responses, testing server availability. dhcptest provides comprehensive testing including lease acquisition, renewal, and release sequences. These tools verify DHCP server configuration and diagnose connectivity issues.
Ruby gems for DHCP interaction include dhcp for low-level packet manipulation, net-dhcp for protocol implementation, and packet for general network packet parsing including DHCP.
Infrastructure Integration: Network management platforms integrate DHCP monitoring and control. Nagios, Zabbix, and Prometheus monitor DHCP pool utilization, lease allocation rates, and server responsiveness. Configuration management tools like Ansible and Puppet automate DHCP server deployment and configuration updates.
# Ansible playbook generation for DHCP configuration
require 'yaml'
class AnsibleDHCPPlaybook
def initialize(inventory)
@inventory = inventory
end
def generate_playbook(subnets)
playbook = [
{
'name' => 'Configure ISC DHCP Server',
'hosts' => 'dhcp_servers',
'become' => true,
'tasks' => [
{
'name' => 'Install ISC DHCP',
'package' => {
'name' => 'isc-dhcp-server',
'state' => 'present'
}
},
{
'name' => 'Configure DHCP',
'template' => {
'src' => 'dhcpd.conf.j2',
'dest' => '/etc/dhcp/dhcpd.conf'
}
},
{
'name' => 'Restart DHCP Service',
'service' => {
'name' => 'isc-dhcp-server',
'state' => 'restarted'
}
}
]
}
]
playbook.to_yaml
end
end
Integration & Interoperability
DHCP integrates deeply with other network services, particularly DNS, forming the foundation of modern network infrastructure.
Dynamic DNS Integration: DHCP servers update DNS records automatically as they assign addresses. When a client receives a lease, the DHCP server sends DNS UPDATE messages to the authoritative DNS server, creating or modifying A (IPv4) and PTR (reverse lookup) records. This dynamic DNS (DDNS) integration maintains DNS consistency without manual intervention.
The DHCP server authenticates DNS updates using TSIG (Transaction Signature), preventing unauthorized record modification. TSIG uses shared secret keys to sign DNS UPDATE messages, verified by the DNS server before accepting changes.
# Representing DDNS configuration
class DDNSConfig
attr_accessor :dns_server, :tsig_key_name, :tsig_algorithm, :tsig_secret
attr_accessor :forward_zone, :reverse_zone
def initialize
@dns_server = '192.168.1.1'
@tsig_algorithm = 'HMAC-SHA256'
@forward_zone = 'example.com'
@reverse_zone = '1.168.192.in-addr.arpa'
end
def update_dns(hostname, ip_address)
forward_update = build_forward_update(hostname, ip_address)
reverse_update = build_reverse_update(hostname, ip_address)
send_dns_update(forward_update)
send_dns_update(reverse_update)
end
private
def build_forward_update(hostname, ip)
# Construct DNS UPDATE message for A record
# Includes TSIG signature
end
def build_reverse_update(hostname, ip)
# Construct DNS UPDATE message for PTR record
# Includes TSIG signature
end
end
DHCP Relay Agent: Relay agents forward DHCP messages between clients and servers on different subnets. Routers typically implement relay functionality, configured with DHCP server IP addresses. When receiving client broadcasts, the relay agent encapsulates them in unicast packets directed to configured servers, inserting the gateway IP address (giaddr field) indicating the client's subnet. Servers use this information to select appropriate address pools and return responses through the relay agent.
# Relay agent message processing
class DHCPRelayAgent
def initialize(server_ips, interfaces)
@server_ips = server_ips
@interfaces = interfaces
end
def process_client_message(message, source_interface)
return unless message.giaddr == '0.0.0.0'
# Set giaddr to interface IP
message.giaddr = @interfaces[source_interface][:ip]
# Forward to all configured DHCP servers
@server_ips.each do |server_ip|
forward_to_server(message, server_ip)
end
end
def process_server_response(message)
# Determine destination interface from giaddr
interface = find_interface_by_ip(message.giaddr)
if message.giaddr == '0.0.0.0'
# Direct to client (same subnet)
forward_to_client(message, message.chaddr)
else
# Forward to relay agent or broadcast
broadcast_to_interface(message, interface)
end
end
end
Network Boot Integration: DHCP supports PXE (Preboot Execution Environment) for network-based system deployment. DHCP options specify boot server addresses and boot file names, enabling diskless workstations and automated OS installation. Option 66 provides the TFTP server hostname, and Option 67 specifies the boot filename.
IPv6 Coexistence: Dual-stack networks run DHCPv4 and DHCPv6 simultaneously. DHCPv6 uses different message types, port numbers (546 for clients, 547 for servers), and addressing schemes. Clients send multicast requests to ff02::1:2 (All_DHCP_Relay_Agents_and_Servers). DHCPv6 prefix delegation enables ISPs to assign IPv6 prefixes to customer networks dynamically.
VPN and Remote Access: Remote access solutions integrate DHCP for client addressing. VPN concentrators act as DHCP clients or relay agents, obtaining addresses for connected users. Split-tunnel VPN configurations use DHCP-provided routes to direct traffic appropriately.
Container and Cloud Environments: Container orchestration platforms implement custom DHCP-like functionality. Kubernetes uses CNI (Container Network Interface) plugins for pod networking, often allocating addresses from defined ranges without traditional DHCP protocols. Cloud platforms provide metadata services accessible at 169.254.169.254, supplying configuration data to instances without DHCP.
IoT and Embedded Systems: Constrained devices use simplified DHCP implementations. DHCP requirements in RFC 2131 allow minimal implementations handling only essential options. Some IoT devices use static addressing or proprietary protocols, though DHCP standardization benefits device portability.
Reference
Message Types
| Type | Value | Direction | Description |
|---|---|---|---|
| DHCPDISCOVER | 1 | Client to Server | Client broadcasts to locate servers |
| DHCPOFFER | 2 | Server to Client | Server responds with offered address |
| DHCPREQUEST | 3 | Client to Server | Client accepts offer or renews lease |
| DHCPDECLINE | 4 | Client to Server | Client rejects offered address |
| DHCPACK | 5 | Server to Client | Server confirms address assignment |
| DHCPNAK | 6 | Server to Client | Server denies client request |
| DHCPRELEASE | 7 | Client to Server | Client releases assigned address |
| DHCPINFORM | 8 | Client to Server | Client requests parameters without address |
Common DHCP Options
| Option | Name | Format | Description |
|---|---|---|---|
| 1 | Subnet Mask | IP Address | Network subnet mask |
| 3 | Router | IP Address List | Default gateway addresses |
| 6 | DNS Server | IP Address List | DNS server addresses |
| 12 | Hostname | String | Client hostname |
| 15 | Domain Name | String | DNS domain name |
| 28 | Broadcast Address | IP Address | Broadcast address for subnet |
| 42 | NTP Server | IP Address List | Network Time Protocol servers |
| 43 | Vendor Specific | Binary | Vendor-specific information |
| 50 | Requested IP | IP Address | Client's requested address |
| 51 | Lease Time | 32-bit Integer | Lease duration in seconds |
| 53 | Message Type | 8-bit Integer | DHCP message type identifier |
| 54 | Server Identifier | IP Address | DHCP server address |
| 55 | Parameter List | Byte Array | Requested option codes |
| 58 | Renewal Time | 32-bit Integer | Time to renewal state |
| 59 | Rebinding Time | 32-bit Integer | Time to rebinding state |
| 61 | Client Identifier | Binary | Unique client identifier |
| 66 | TFTP Server | String | TFTP server hostname |
| 67 | Boot Filename | String | Boot file name |
Packet Structure Fields
| Field | Offset | Length | Description |
|---|---|---|---|
| op | 0 | 1 byte | Message operation code (1=request, 2=reply) |
| htype | 1 | 1 byte | Hardware address type (1=Ethernet) |
| hlen | 2 | 1 byte | Hardware address length |
| hops | 3 | 1 byte | Relay agent hop count |
| xid | 4 | 4 bytes | Transaction identifier |
| secs | 8 | 2 bytes | Seconds since client began address acquisition |
| flags | 10 | 2 bytes | Flags (broadcast bit) |
| ciaddr | 12 | 4 bytes | Client IP address |
| yiaddr | 16 | 4 bytes | Your (client) IP address |
| siaddr | 20 | 4 bytes | Server IP address |
| giaddr | 24 | 4 bytes | Gateway IP address (relay agent) |
| chaddr | 28 | 16 bytes | Client hardware address |
| sname | 44 | 64 bytes | Server hostname |
| file | 108 | 128 bytes | Boot filename |
| options | 236 | Variable | DHCP options (starts with magic cookie) |
Lease State Transitions
| Current State | Timer | Event | Next State |
|---|---|---|---|
| INIT | - | Interface up | SELECTING |
| SELECTING | - | Send DISCOVER | SELECTING |
| SELECTING | Timeout | Receive OFFER | REQUESTING |
| REQUESTING | - | Send REQUEST | REQUESTING |
| REQUESTING | Timeout | Receive ACK | BOUND |
| BOUND | T1 expires | - | RENEWING |
| RENEWING | - | Send REQUEST (unicast) | RENEWING |
| RENEWING | T2 expires | - | REBINDING |
| REBINDING | - | Send REQUEST (broadcast) | REBINDING |
| REBINDING | Lease expires | - | INIT |
| BOUND/RENEWING/REBINDING | - | Receive NAK | INIT |
Port Assignments
| Component | Port | Protocol | Purpose |
|---|---|---|---|
| DHCP Server | 67 | UDP | Receives client requests |
| DHCP Client | 68 | UDP | Receives server responses |
| DHCPv6 Server | 547 | UDP | Receives DHCPv6 requests |
| DHCPv6 Client | 546 | UDP | Receives DHCPv6 responses |
Timing Parameters
| Parameter | Typical Value | Description |
|---|---|---|
| Default Lease Time | 86400 seconds (24 hours) | Standard lease duration |
| Max Lease Time | 604800 seconds (7 days) | Maximum allowed lease duration |
| T1 (Renewal) | 50% of lease time | Time until renewal attempt |
| T2 (Rebinding) | 87.5% of lease time | Time until rebinding attempt |
| Discover Retry | 4 seconds (exponential backoff) | Time between discovery attempts |
| Request Retry | 4 seconds (exponential backoff) | Time between request attempts |
Ruby Code Reference
# Basic DHCP packet structure
class DHCPPacket
attr_accessor :op, :htype, :hlen, :hops, :xid, :secs, :flags
attr_accessor :ciaddr, :yiaddr, :siaddr, :giaddr, :chaddr
attr_accessor :sname, :file, :options
BOOTREQUEST = 1
BOOTREPLY = 2
MAGIC_COOKIE = [0x63, 0x82, 0x53, 0x63]
def initialize
@options = {}
end
def pack
# Pack struct into binary format
packet = [
@op, @htype, @hlen, @hops
].pack('C4')
packet += [@xid].pack('N')
packet += [@secs, @flags].pack('n2')
# ... continue with remaining fields
end
def self.unpack(data)
# Parse binary data into DHCPPacket
packet = new
fields = data.unpack('C4Na2Nn4a16a64a128a*')
# ... assign fields to packet attributes
packet
end
end