CrackedRuby CrackedRuby

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