dhcp4c

package
v0.0.0-...-5fb8a3f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 30, 2024 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package dhcp4c implements a DHCPv4 Client as specified in RFC2131 (with some notable deviations). It implements only the DHCP state machine itself, any configuration other than the interface IP address (which is always assigned in DHCP and necessary for the protocol to work) is exposed as [informers/observables/watchable variables/???] to consumers who then deal with it.

Package dhcp4c provides a client implementation of the DHCPv4 protocol (RFC2131) and a few extensions for Linux-based systems. The code is split into three main parts:

  • The core DHCP state machine, which lives in dhcpc.go
  • Mechanisms to send and receive DHCP messages, which live in transport/
  • Standard callbacks which implement necessary kernel configuration steps in a simple and standalone way living in callback/

Since the DHCP protocol is ugly and underspecified (see https://tools.ietf.org/html/draft-ietf-dhc-implementation-02 for a subset of known issues), this client slightly bends the specification in the following cases:

  • IP fragmentation for DHCP messages is not supported for both sending and receiving messages This is because the major servers (ISC, dnsmasq, ...) do not implement it and just drop fragmented packets, so it would be counterproductive to try to send them. The client just attempts to send the full message and hopes it passes through to the server.
  • The suggested timeouts and wait periods have been tightened significantly. When the standard was written 10Mbps Ethernet with hubs was a common interconnect. Using these would make the client extremely slow on today's 1Gbps+ networks.
  • Wrong data in DHCP responses is fixed up if possible. This fixing includes dropping prohibited options, clamping semantically invalid data and defaulting not set options as far as it's possible. Non-recoverable responses (for example because a non-Unicast IP is handed out or lease time is not set or zero) are still ignored. All data which can be stored in both DHCP fields and options is also normalized to the corresponding option.
  • Duplicate Address Detection is not implemented by default. It's slow, hard to implement correctly and generally not necessary on modern networks as the servers already waste time checking for duplicate addresses. It's possible to hook it in via a LeaseCallback if necessary in a given application.

Operationally, there's one known caveat to using this client: If the lease offered during the select phase (in a DHCPOFFER) is not the same as the one sent in the following DHCPACK the first one might be acceptable, but the second one might not be. This can cause pathological behavior where the client constantly switches between discovering and requesting states. Depending on the reuse policies on the DHCP server this can cause the client to consume all available IP addresses. Sadly there's no good way of fixing this within the boundaries of the protocol. A DHCPRELEASE for the adresse would need to be unicasted so the unaccepable address would need to be configured which can be either impossible if it's not valid or not acceptable from a security standpoint (for example because it overlaps with a prefix used internally) and a DHCPDECLINE would cause the server to blacklist the IP thus also depleting the IP pool. This could be potentially avoided by originating DHCPRELEASE packages from a userspace transport, but said transport would need to be routing- and PMTU-aware which would make it even more complicated than the existing BroadcastTransport.

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidMsg = errors.New("invalid message")

Functions

This section is empty.

Types

type BroadcastTransport

type BroadcastTransport interface {
	Transport
	// Open connects the transport. Can only be called after calling Close() or
	// after creating a new transport.
	Open() error
}

BroadcastTransport represents a mechanism over which DHCP messages can be exchanged with all servers on a Layer 2 broadcast domain. Implementers need to support sending and receiving messages without any IP being configured on the interface.

type Client

type Client struct {
	// RequestedOptions contains a list of extra options this client is
	// interested in
	RequestedOptions dhcpv4.OptionCodeList

	// ClientIdentifier is used by the DHCP server to identify this client.
	// If empty, on Ethernet the MAC address is used instead.
	ClientIdentifier []byte

	// VendorClassIdentifier is used by the DHCP server to identify options
	// specific to this type of clients and to populate the vendor-specific
	// option (43).
	VendorClassIdentifier string

	// ExtraRequestOptions are extra options sent to the server.
	ExtraRequestOptions dhcpv4.Options

	// Backoff strategies for each state. These all have sane defaults,
	// override them only if necessary.
	DiscoverBackoff    backoff.BackOff
	AcceptOfferBackoff backoff.BackOff
	RenewBackoff       backoff.BackOff
	RebindBackoff      backoff.BackOff

	// LeaseCallback is called every time a lease is aquired, renewed or lost
	LeaseCallback LeaseCallback
	// contains filtered or unexported fields
}

Client implements a DHCPv4 client.

Note that the size of all data sent to the server (RequestedOptions, ClientIdentifier, VendorClassIdentifier and ExtraRequestOptions) should be kept reasonably small (<500 bytes) in order to maximize the chance that requests can be properly transmitted.

func NewClient

func NewClient(iface *net.Interface) (*Client, error)

NewClient instantiates (but doesn't start) a new DHCPv4 client. To have a working client it's required to set LeaseCallback to something that is capable of configuring the IP address on the given interface. Unless managed through external means like a routing protocol, setting the default route is also required. A simple example with the callback package thus looks like this:

c := dhcp4c.NewClient(yourInterface)
c.LeaseCallback = callback.Compose(callback.ManageIP(yourInterface), callback.ManageDefaultRoute(yourInterface))
c.Run(ctx)

func (*Client) Run

func (c *Client) Run(ctx context.Context) error

type DNSServers

type DNSServers []net.IP

DNSServers represents an ordered collection of DNS servers

func (DNSServers) Equal

func (a DNSServers) Equal(b DNSServers) bool

type Lease

type Lease struct {
	AssignedIP net.IP
	ExpiresAt  time.Time
	Options    dhcpv4.Options
}

Lease represents a DHCPv4 lease. It only consists of an IP, an expiration timestamp and options as all other relevant parts of the message have been normalized into their respective options. It also contains some smart getters for commonly-used options which extract only valid information from options.

func (*Lease) DNSServers

func (l *Lease) DNSServers() DNSServers

DNSServers returns all unique valid DNS servers from the DHCP DomainNameServers options. It returns nil if the lease is nil.

func (*Lease) IPNet

func (l *Lease) IPNet() *net.IPNet

IPNet returns an IPNet from the assigned IP and subnet mask. It returns nil if the lease is nil.

func (*Lease) Routes

func (l *Lease) Routes() []*dhcpv4.Route

Routes returns all routes assigned by a DHCP answer. It combines and normalizes data from the Router, StaticRoutingTable and ClasslessStaticRoute options.

func (*Lease) SubnetMask

func (l *Lease) SubnetMask() net.IPMask

SubnetMask returns the SubnetMask option or the default mask if not set or invalid. It returns nil if the lease is nil.

type LeaseCallback

type LeaseCallback func(*Lease) error

type Transport

type Transport interface {
	// Send attempts to send the given DHCP payload message to the transport
	// target once. An empty return value does not indicate that the message
	// was successfully received.
	Send(payload *dhcpv4.DHCPv4) error
	// SetReceiveDeadline sets a deadline for Receive() calls after which they
	// return with ErrDeadlineExceeded
	SetReceiveDeadline(time.Time) error
	// Receive waits for a DHCP message to arrive and returns it. If the
	// deadline expires without a message arriving it will return
	// ErrDeadlineExceeded. If the message is completely malformed it will an
	// instance of InvalidMessageError.
	Receive() (*dhcpv4.DHCPv4, error)
	// Close closes the given transport. Calls to any of the above methods will
	// fail if the transport is closed.  Specific transports can be reopened
	// after being closed.
	Close() error
}

Transport represents a mechanism over which DHCP messages can be exchanged with a server.

type UnicastTransport

type UnicastTransport interface {
	Transport
	// Open connects the transport to a new unicast target. Can only be called
	// after calling Close() or after creating a new transport.
	Open(serverIP, bindIP net.IP) error
}

UnicastTransport represents a mechanism over which DHCP messages can be exchanged with a single server over an arbitrary IPv4-based network. Implementers need to support servers running outside the local network via a router.

Directories

Path Synopsis
Package callback contains minimal callbacks for configuring the kernel with options received over DHCP.
Package callback contains minimal callbacks for configuring the kernel with options received over DHCP.
Package transport contains Linux-based transports for the DHCP broadcast and unicast specifications.
Package transport contains Linux-based transports for the DHCP broadcast and unicast specifications.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL