Update dependencies

This commit is contained in:
bluepython508
2024-11-01 17:33:34 +00:00
parent 033ac0b400
commit 5cdfab398d
3596 changed files with 1033483 additions and 259 deletions

View File

@@ -0,0 +1,10 @@
package dhcpv4
import (
"github.com/insomniacslk/dhcp/interfaces"
)
// BindToInterface (deprecated) redirects to interfaces.BindToInterface
func BindToInterface(fd int, ifname string) error {
return interfaces.BindToInterface(fd, ifname)
}

View File

@@ -0,0 +1,6 @@
package dhcpv4
const (
ServerPort = 67
ClientPort = 68
)

831
vendor/github.com/insomniacslk/dhcp/dhcpv4/dhcpv4.go generated vendored Normal file
View File

@@ -0,0 +1,831 @@
// Package dhcpv4 provides encoding and decoding of DHCPv4 packets and options.
//
// Example Usage:
//
// p, err := dhcpv4.New(
// dhcpv4.WithClientIP(net.IP{192, 168, 0, 1}),
// dhcpv4.WithMessageType(dhcpv4.MessageTypeInform),
// )
// p.UpdateOption(dhcpv4.OptServerIdentifier(net.IP{192, 110, 110, 110}))
//
// // Retrieve the DHCP Message Type option.
// m := p.MessageType()
//
// bytesOnTheWire := p.ToBytes()
// longSummary := p.Summary()
package dhcpv4
import (
"bytes"
"context"
"errors"
"fmt"
"net"
"strings"
"time"
"github.com/insomniacslk/dhcp/iana"
"github.com/insomniacslk/dhcp/rfc1035label"
"github.com/u-root/uio/rand"
"github.com/u-root/uio/uio"
)
const (
// minPacketLen is the minimum DHCP header length.
minPacketLen = 236
// MaxHWAddrLen is the maximum hardware address length of the ClientHWAddr
// (client hardware address) according to RFC 2131, Section 2. This is the
// link-layer destination a server must send responses to.
MaxHWAddrLen = 16
// MaxMessageSize is the maximum size in bytes that a DHCPv4 packet can hold.
MaxMessageSize = 576
// Per RFC 951, the minimum length of a packet is 300 bytes.
bootpMinLen = 300
)
// RandomTimeout is the amount of time to wait until random number generation
// is canceled.
var RandomTimeout = 2 * time.Minute
// magicCookie is the magic 4-byte value at the beginning of the list of options
// in a DHCPv4 packet.
var magicCookie = [4]byte{99, 130, 83, 99}
// DHCPv4 represents a DHCPv4 packet header and options. See the New* functions
// to build DHCPv4 packets.
type DHCPv4 struct {
OpCode OpcodeType
HWType iana.HWType
HopCount uint8
TransactionID TransactionID
NumSeconds uint16
Flags uint16
ClientIPAddr net.IP
YourIPAddr net.IP
ServerIPAddr net.IP
GatewayIPAddr net.IP
ClientHWAddr net.HardwareAddr
ServerHostName string
BootFileName string
Options Options
}
// Modifier defines the signature for functions that can modify DHCPv4
// structures. This is used to simplify packet manipulation
type Modifier func(d *DHCPv4)
// IPv4AddrsForInterface obtains the currently-configured, non-loopback IPv4
// addresses for iface.
func IPv4AddrsForInterface(iface *net.Interface) ([]net.IP, error) {
if iface == nil {
return nil, errors.New("IPv4AddrsForInterface: iface cannot be nil")
}
addrs, err := iface.Addrs()
if err != nil {
return nil, err
}
return GetExternalIPv4Addrs(addrs)
}
// GetExternalIPv4Addrs obtains the currently-configured, non-loopback IPv4
// addresses from `addrs` coming from a particular interface (e.g.
// net.Interface.Addrs).
func GetExternalIPv4Addrs(addrs []net.Addr) ([]net.IP, error) {
var v4addrs []net.IP
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPAddr:
ip = v.IP
case *net.IPNet:
ip = v.IP
}
if ip == nil || ip.IsLoopback() {
continue
}
ip = ip.To4()
if ip == nil {
continue
}
v4addrs = append(v4addrs, ip)
}
return v4addrs, nil
}
// GenerateTransactionID generates a random 32-bits number suitable for use as
// TransactionID
func GenerateTransactionID() (TransactionID, error) {
var xid TransactionID
ctx, cancel := context.WithTimeout(context.Background(), RandomTimeout)
defer cancel()
n, err := rand.ReadContext(ctx, xid[:])
if err != nil {
return xid, fmt.Errorf("could not get random number: %v", err)
}
if n != 4 {
return xid, errors.New("invalid random sequence for transaction ID: smaller than 32 bits")
}
return xid, err
}
// New creates a new DHCPv4 structure and fill it up with default values. It
// won't be a valid DHCPv4 message so you will need to adjust its fields.
// See also NewDiscovery, NewRequest, NewAcknowledge, NewInform and NewRelease.
func New(modifiers ...Modifier) (*DHCPv4, error) {
xid, err := GenerateTransactionID()
if err != nil {
return nil, err
}
d := DHCPv4{
OpCode: OpcodeBootRequest,
HWType: iana.HWTypeEthernet,
ClientHWAddr: make(net.HardwareAddr, 6),
HopCount: 0,
TransactionID: xid,
NumSeconds: 0,
Flags: 0,
ClientIPAddr: net.IPv4zero,
YourIPAddr: net.IPv4zero,
ServerIPAddr: net.IPv4zero,
GatewayIPAddr: net.IPv4zero,
Options: make(Options),
}
for _, mod := range modifiers {
mod(&d)
}
return &d, nil
}
// NewDiscoveryForInterface builds a new DHCPv4 Discovery message, with a default
// Ethernet HW type and the hardware address obtained from the specified
// interface.
func NewDiscoveryForInterface(ifname string, modifiers ...Modifier) (*DHCPv4, error) {
iface, err := net.InterfaceByName(ifname)
if err != nil {
return nil, err
}
return NewDiscovery(iface.HardwareAddr, modifiers...)
}
// NewDiscovery builds a new DHCPv4 Discovery message, with a default Ethernet
// HW type and specified hardware address.
func NewDiscovery(hwaddr net.HardwareAddr, modifiers ...Modifier) (*DHCPv4, error) {
return New(PrependModifiers(modifiers,
WithHwAddr(hwaddr),
WithRequestedOptions(
OptionSubnetMask,
OptionRouter,
OptionDomainName,
OptionDomainNameServer,
),
WithMessageType(MessageTypeDiscover),
)...)
}
// NewInformForInterface builds a new DHCPv4 Informational message with default
// Ethernet HW type and the hardware address obtained from the specified
// interface.
func NewInformForInterface(ifname string, needsBroadcast bool) (*DHCPv4, error) {
// get hw addr
iface, err := net.InterfaceByName(ifname)
if err != nil {
return nil, err
}
// Set Client IP as iface's currently-configured IP.
localIPs, err := IPv4AddrsForInterface(iface)
if err != nil || len(localIPs) == 0 {
return nil, fmt.Errorf("could not get local IPs for iface %s", ifname)
}
pkt, err := NewInform(iface.HardwareAddr, localIPs[0])
if err != nil {
return nil, err
}
if needsBroadcast {
pkt.SetBroadcast()
} else {
pkt.SetUnicast()
}
return pkt, nil
}
// PrependModifiers prepends other to m.
func PrependModifiers(m []Modifier, other ...Modifier) []Modifier {
return append(other, m...)
}
// NewInform builds a new DHCPv4 Informational message with the specified
// hardware address.
func NewInform(hwaddr net.HardwareAddr, localIP net.IP, modifiers ...Modifier) (*DHCPv4, error) {
return New(PrependModifiers(modifiers,
WithHwAddr(hwaddr),
WithMessageType(MessageTypeInform),
WithClientIP(localIP),
)...)
}
// NewRequestFromOffer builds a DHCPv4 request from an offer.
// It assumes the SELECTING state by default, see Section 4.3.2 in RFC 2131 for more details.
func NewRequestFromOffer(offer *DHCPv4, modifiers ...Modifier) (*DHCPv4, error) {
return New(PrependModifiers(modifiers,
WithReply(offer),
WithMessageType(MessageTypeRequest),
WithClientIP(offer.ClientIPAddr),
WithOption(OptRequestedIPAddress(offer.YourIPAddr)),
// This is usually the server IP.
WithOptionCopied(offer, OptionServerIdentifier),
WithRequestedOptions(
OptionSubnetMask,
OptionRouter,
OptionDomainName,
OptionDomainNameServer,
),
)...)
}
// NewRenewFromAck builds a DHCPv4 RENEW-style request from the ACK of a lease. RENEW requests have
// minor changes to their options compared to SELECT requests as specified by RFC 2131, section 4.3.2.
func NewRenewFromAck(ack *DHCPv4, modifiers ...Modifier) (*DHCPv4, error) {
return New(PrependModifiers(modifiers,
WithReply(ack),
WithMessageType(MessageTypeRequest),
// The client IP must be filled in with the IP offered to the client
WithClientIP(ack.YourIPAddr),
// The renewal request must use unicast
WithBroadcast(false),
WithRequestedOptions(
OptionSubnetMask,
OptionRouter,
OptionDomainName,
OptionDomainNameServer,
),
)...)
}
// NewReplyFromRequest builds a DHCPv4 reply from a request.
func NewReplyFromRequest(request *DHCPv4, modifiers ...Modifier) (*DHCPv4, error) {
return New(PrependModifiers(modifiers,
WithReply(request),
WithGatewayIP(request.GatewayIPAddr),
WithOptionCopied(request, OptionRelayAgentInformation),
// RFC 6842 states the Client Identifier option must be copied
// from the request if a client specified it.
WithOptionCopied(request, OptionClientIdentifier),
)...)
}
// NewReleaseFromACK creates a DHCPv4 Release message from ACK.
// default Release message without any Modifer is created as following:
// - option Message Type is Release
// - ClientIP is set to ack.YourIPAddr
// - ClientHWAddr is set to ack.ClientHWAddr
// - Unicast
// - option Server Identifier is set to ack's ServerIdentifier
func NewReleaseFromACK(ack *DHCPv4, modifiers ...Modifier) (*DHCPv4, error) {
return New(PrependModifiers(modifiers,
WithMessageType(MessageTypeRelease),
WithClientIP(ack.YourIPAddr),
WithHwAddr(ack.ClientHWAddr),
WithBroadcast(false),
WithOptionCopied(ack, OptionServerIdentifier),
)...)
}
// FromBytes decodes a DHCPv4 packet from a sequence of bytes, and returns an
// error if the packet is not valid.
func FromBytes(q []byte) (*DHCPv4, error) {
var p DHCPv4
buf := uio.NewBigEndianBuffer(q)
p.OpCode = OpcodeType(buf.Read8())
p.HWType = iana.HWType(buf.Read8())
hwAddrLen := buf.Read8()
p.HopCount = buf.Read8()
buf.ReadBytes(p.TransactionID[:])
p.NumSeconds = buf.Read16()
p.Flags = buf.Read16()
p.ClientIPAddr = net.IP(buf.CopyN(net.IPv4len))
p.YourIPAddr = net.IP(buf.CopyN(net.IPv4len))
p.ServerIPAddr = net.IP(buf.CopyN(net.IPv4len))
p.GatewayIPAddr = net.IP(buf.CopyN(net.IPv4len))
if hwAddrLen > 16 {
hwAddrLen = 16
}
// Always read 16 bytes, but only use hwaddrlen of them.
p.ClientHWAddr = make(net.HardwareAddr, 16)
buf.ReadBytes(p.ClientHWAddr)
p.ClientHWAddr = p.ClientHWAddr[:hwAddrLen]
var sname [64]byte
buf.ReadBytes(sname[:])
length := strings.Index(string(sname[:]), "\x00")
if length == -1 {
length = 64
}
p.ServerHostName = string(sname[:length])
var file [128]byte
buf.ReadBytes(file[:])
length = strings.Index(string(file[:]), "\x00")
if length == -1 {
length = 128
}
p.BootFileName = string(file[:length])
var cookie [4]byte
buf.ReadBytes(cookie[:])
if err := buf.Error(); err != nil {
return nil, err
}
if cookie != magicCookie {
return nil, fmt.Errorf("malformed DHCP packet: got magic cookie %v, want %v", cookie[:], magicCookie[:])
}
p.Options = make(Options)
if err := p.Options.fromBytesCheckEnd(buf.Data(), true); err != nil {
return nil, err
}
return &p, nil
}
// FlagsToString returns a human-readable representation of the flags field.
func (d *DHCPv4) FlagsToString() string {
flags := ""
if d.IsBroadcast() {
flags += "Broadcast"
} else {
flags += "Unicast"
}
if d.Flags&0xfe != 0 {
flags += " (reserved bits not zeroed)"
}
return flags
}
// IsBroadcast indicates whether the packet is a broadcast packet.
func (d *DHCPv4) IsBroadcast() bool {
return d.Flags&0x8000 == 0x8000
}
// SetBroadcast sets the packet to be a broadcast packet.
func (d *DHCPv4) SetBroadcast() {
d.Flags |= 0x8000
}
// IsUnicast indicates whether the packet is a unicast packet.
func (d *DHCPv4) IsUnicast() bool {
return d.Flags&0x8000 == 0
}
// SetUnicast sets the packet to be a unicast packet.
func (d *DHCPv4) SetUnicast() {
d.Flags &= ^uint16(0x8000)
}
// GetOneOption returns the option that matches the given option code.
//
// According to RFC 3396, options that are specified more than once are
// concatenated, and hence this should always just return one option.
func (d *DHCPv4) GetOneOption(code OptionCode) []byte {
return d.Options.Get(code)
}
// DeleteOption deletes an existing option with the given option code.
func (d *DHCPv4) DeleteOption(code OptionCode) {
if d.Options != nil {
d.Options.Del(code)
}
}
// UpdateOption replaces an existing option with the same option code with the
// given one, adding it if not already present.
func (d *DHCPv4) UpdateOption(opt Option) {
if d.Options == nil {
d.Options = make(Options)
}
d.Options.Update(opt)
}
// String implements fmt.Stringer.
func (d *DHCPv4) String() string {
return fmt.Sprintf("DHCPv4(xid=%s hwaddr=%s msg_type=%s, your_ip=%s, server_ip=%s)",
d.TransactionID, d.ClientHWAddr, d.MessageType(), d.YourIPAddr, d.ServerIPAddr)
}
// SummaryWithVendor prints a summary of the packet, interpreting the
// vendor-specific info option using the given parser (can be nil).
func (d *DHCPv4) SummaryWithVendor(vendorDecoder OptionDecoder) string {
ret := fmt.Sprintf(
"DHCPv4 Message\n"+
" opcode: %s\n"+
" hwtype: %s\n"+
" hopcount: %v\n"+
" transaction ID: %s\n"+
" num seconds: %v\n"+
" flags: %v (0x%02x)\n"+
" client IP: %s\n"+
" your IP: %s\n"+
" server IP: %s\n"+
" gateway IP: %s\n"+
" client MAC: %s\n"+
" server hostname: %s\n"+
" bootfile name: %s\n",
d.OpCode,
d.HWType,
d.HopCount,
d.TransactionID,
d.NumSeconds,
d.FlagsToString(),
d.Flags,
d.ClientIPAddr,
d.YourIPAddr,
d.ServerIPAddr,
d.GatewayIPAddr,
d.ClientHWAddr,
d.ServerHostName,
d.BootFileName,
)
ret += " options:\n"
ret += d.Options.Summary(vendorDecoder)
return ret
}
// Summary prints detailed information about the packet.
func (d *DHCPv4) Summary() string {
return d.SummaryWithVendor(nil)
}
// IsOptionRequested returns true if that option is within the requested
// options of the DHCPv4 message.
func (d *DHCPv4) IsOptionRequested(requested OptionCode) bool {
rq := d.ParameterRequestList()
if rq == nil {
// RFC2131§3.5
// Not all clients require initialization of all parameters [...]
// Two techniques are used to reduce the number of parameters transmitted from
// the server to the client. [...] Second, in its initial DHCPDISCOVER or
// DHCPREQUEST message, a client may provide the server with a list of specific
// parameters the client is interested in.
// We interpret this to say that all available parameters should be sent if
// the parameter request list is not sent at all.
return true
}
for _, o := range rq {
if o == requested {
return true
}
}
return false
}
// In case somebody forgets to set an IP, just write 0s as default values.
func writeIP(b *uio.Lexer, ip net.IP) {
var zeros [net.IPv4len]byte
if ip == nil {
b.WriteBytes(zeros[:])
} else {
// Converting IP to 4 byte format
ip = ip.To4()
b.WriteBytes(ip[:net.IPv4len])
}
}
// ToBytes writes the packet to binary.
func (d *DHCPv4) ToBytes() []byte {
buf := uio.NewBigEndianBuffer(make([]byte, 0, minPacketLen))
buf.Write8(uint8(d.OpCode))
buf.Write8(uint8(d.HWType))
// HwAddrLen
hlen := uint8(len(d.ClientHWAddr))
buf.Write8(hlen)
buf.Write8(d.HopCount)
buf.WriteBytes(d.TransactionID[:])
buf.Write16(d.NumSeconds)
buf.Write16(d.Flags)
writeIP(buf, d.ClientIPAddr)
writeIP(buf, d.YourIPAddr)
writeIP(buf, d.ServerIPAddr)
writeIP(buf, d.GatewayIPAddr)
copy(buf.WriteN(16), d.ClientHWAddr)
var sname [64]byte
copy(sname[:63], []byte(d.ServerHostName))
buf.WriteBytes(sname[:])
var file [128]byte
copy(file[:127], []byte(d.BootFileName))
buf.WriteBytes(file[:])
// The magic cookie.
buf.WriteBytes(magicCookie[:])
// Write all options.
d.Options.Marshal(buf)
// Finish the options.
buf.Write8(OptionEnd.Code())
// DHCP is based on BOOTP, and BOOTP messages have a minimum length of
// 300 bytes per RFC 951. This not stated explicitly, but if you sum up
// all the bytes in the message layout, you'll get 300 bytes.
//
// Some DHCP servers and relay agents care about this BOOTP legacy B.S.
// and "conveniently" drop messages that are less than 300 bytes long.
if buf.Len() < bootpMinLen {
buf.WriteBytes(bytes.Repeat([]byte{OptionPad.Code()}, bootpMinLen-buf.Len()))
}
return buf.Data()
}
// GetBroadcastAddress returns the DHCPv4 Broadcast Address value in d.
//
// The broadcast address option is described in RFC 2132, Section 5.3.
func (d *DHCPv4) BroadcastAddress() net.IP {
return GetIP(OptionBroadcastAddress, d.Options)
}
// RequestedIPAddress returns the DHCPv4 Requested IP Address value in d.
//
// The requested IP address option is described by RFC 2132, Section 9.1.
func (d *DHCPv4) RequestedIPAddress() net.IP {
return GetIP(OptionRequestedIPAddress, d.Options)
}
// ServerIdentifier returns the DHCPv4 Server Identifier value in d.
//
// The server identifier option is described by RFC 2132, Section 9.7.
func (d *DHCPv4) ServerIdentifier() net.IP {
return GetIP(OptionServerIdentifier, d.Options)
}
// Router parses the DHCPv4 Router option if present.
//
// The Router option is described by RFC 2132, Section 3.5.
func (d *DHCPv4) Router() []net.IP {
return GetIPs(OptionRouter, d.Options)
}
// ClasslessStaticRoute parses the DHCPv4 Classless Static Route option if present.
//
// The Classless Static Route option is described by RFC 3442.
func (d *DHCPv4) ClasslessStaticRoute() []*Route {
v := d.Options.Get(OptionClasslessStaticRoute)
if v == nil {
return nil
}
var routes Routes
if err := routes.FromBytes(v); err != nil {
return nil
}
return routes
}
// NTPServers parses the DHCPv4 NTP Servers option if present.
//
// The NTP servers option is described by RFC 2132, Section 8.3.
func (d *DHCPv4) NTPServers() []net.IP {
return GetIPs(OptionNTPServers, d.Options)
}
// DNS parses the DHCPv4 Domain Name Server option if present.
//
// The DNS server option is described by RFC 2132, Section 3.8.
func (d *DHCPv4) DNS() []net.IP {
return GetIPs(OptionDomainNameServer, d.Options)
}
// DomainName parses the DHCPv4 Domain Name option if present.
//
// The Domain Name option is described by RFC 2132, Section 3.17.
func (d *DHCPv4) DomainName() string {
return GetString(OptionDomainName, d.Options)
}
// HostName parses the DHCPv4 Host Name option if present.
//
// The Host Name option is described by RFC 2132, Section 3.14.
func (d *DHCPv4) HostName() string {
name := GetString(OptionHostName, d.Options)
return strings.TrimRight(name, "\x00")
}
// RootPath parses the DHCPv4 Root Path option if present.
//
// The Root Path option is described by RFC 2132, Section 3.19.
func (d *DHCPv4) RootPath() string {
return GetString(OptionRootPath, d.Options)
}
// BootFileNameOption parses the DHCPv4 Bootfile Name option if present.
//
// The Bootfile Name option is described by RFC 2132, Section 9.5.
func (d *DHCPv4) BootFileNameOption() string {
name := GetString(OptionBootfileName, d.Options)
return strings.TrimRight(name, "\x00")
}
// TFTPServerName parses the DHCPv4 TFTP Server Name option if present.
//
// The TFTP Server Name option is described by RFC 2132, Section 9.4.
func (d *DHCPv4) TFTPServerName() string {
name := GetString(OptionTFTPServerName, d.Options)
return strings.TrimRight(name, "\x00")
}
// ClassIdentifier parses the DHCPv4 Class Identifier option if present.
//
// The Vendor Class Identifier option is described by RFC 2132, Section 9.13.
func (d *DHCPv4) ClassIdentifier() string {
return GetString(OptionClassIdentifier, d.Options)
}
// ClientArch returns the Client System Architecture Type option.
func (d *DHCPv4) ClientArch() []iana.Arch {
v := d.Options.Get(OptionClientSystemArchitectureType)
if v == nil {
return nil
}
var archs iana.Archs
if err := archs.FromBytes(v); err != nil {
return nil
}
return archs
}
// DomainSearch returns the domain search list if present.
//
// The domain search option is described by RFC 3397, Section 2.
func (d *DHCPv4) DomainSearch() *rfc1035label.Labels {
v := d.Options.Get(OptionDNSDomainSearchList)
if v == nil {
return nil
}
labels, err := rfc1035label.FromBytes(v)
if err != nil {
return nil
}
return labels
}
// IPAddressLeaseTime returns the IP address lease time or the given
// default duration if not present.
//
// The IP address lease time option is described by RFC 2132, Section 9.2.
func (d *DHCPv4) IPAddressLeaseTime(def time.Duration) time.Duration {
v := d.Options.Get(OptionIPAddressLeaseTime)
if v == nil {
return def
}
var dur Duration
if err := dur.FromBytes(v); err != nil {
return def
}
return time.Duration(dur)
}
// IPAddressRenewalTime returns the IP address renewal time or the given
// default duration if not present.
//
// The IP address renewal time option is described by RFC 2132, Section 9.11.
func (d *DHCPv4) IPAddressRenewalTime(def time.Duration) time.Duration {
v := d.Options.Get(OptionRenewTimeValue)
if v == nil {
return def
}
var dur Duration
if err := dur.FromBytes(v); err != nil {
return def
}
return time.Duration(dur)
}
// IPAddressRebindingTime returns the IP address rebinding time or the given
// default duration if not present.
//
// The IP address rebinding time option is described by RFC 2132, Section 9.12.
func (d *DHCPv4) IPAddressRebindingTime(def time.Duration) time.Duration {
v := d.Options.Get(OptionRebindingTimeValue)
if v == nil {
return def
}
var dur Duration
if err := dur.FromBytes(v); err != nil {
return def
}
return time.Duration(dur)
}
// MaxMessageSize returns the DHCP Maximum Message Size if present.
//
// The Maximum DHCP Message Size option is described by RFC 2132, Section 9.10.
func (d *DHCPv4) MaxMessageSize() (uint16, error) {
return GetUint16(OptionMaximumDHCPMessageSize, d.Options)
}
// MessageType returns the DHCPv4 Message Type option.
func (d *DHCPv4) MessageType() MessageType {
v := d.Options.Get(OptionDHCPMessageType)
if v == nil {
return MessageTypeNone
}
var m MessageType
if err := m.FromBytes(v); err != nil {
return MessageTypeNone
}
return m
}
// Message returns the DHCPv4 (Error) Message option.
//
// The message options is described in RFC 2132, Section 9.9.
func (d *DHCPv4) Message() string {
return GetString(OptionMessage, d.Options)
}
// ParameterRequestList returns the DHCPv4 Parameter Request List.
//
// The parameter request list option is described by RFC 2132, Section 9.8.
func (d *DHCPv4) ParameterRequestList() OptionCodeList {
v := d.Options.Get(OptionParameterRequestList)
if v == nil {
return nil
}
var codes OptionCodeList
if err := codes.FromBytes(v); err != nil {
return nil
}
return codes
}
// RelayAgentInfo returns options embedded by the relay agent.
//
// The relay agent info option is described by RFC 3046.
func (d *DHCPv4) RelayAgentInfo() *RelayOptions {
v := d.Options.Get(OptionRelayAgentInformation)
if v == nil {
return nil
}
var relayOptions RelayOptions
if err := relayOptions.FromBytes(v); err != nil {
return nil
}
return &relayOptions
}
// SubnetMask returns a subnet mask option contained if present.
//
// The subnet mask option is described by RFC 2132, Section 3.3.
func (d *DHCPv4) SubnetMask() net.IPMask {
v := d.Options.Get(OptionSubnetMask)
if v == nil {
return nil
}
var im IPMask
if err := im.FromBytes(v); err != nil {
return nil
}
return net.IPMask(im)
}
// UserClass returns the user class if present.
//
// The user class information option is defined by RFC 3004.
func (d *DHCPv4) UserClass() []string {
v := d.Options.Get(OptionUserClassInformation)
if v == nil {
return nil
}
var uc Strings
if err := uc.FromBytes(v); err != nil {
return []string{GetString(OptionUserClassInformation, d.Options)}
}
return uc
}
// VIVC returns the vendor-identifying vendor class option if present.
func (d *DHCPv4) VIVC() VIVCIdentifiers {
v := d.Options.Get(OptionVendorIdentifyingVendorClass)
if v == nil {
return nil
}
var ids VIVCIdentifiers
if err := ids.FromBytes(v); err != nil {
return nil
}
return ids
}

171
vendor/github.com/insomniacslk/dhcp/dhcpv4/modifiers.go generated vendored Normal file
View File

@@ -0,0 +1,171 @@
package dhcpv4
import (
"net"
"time"
"github.com/insomniacslk/dhcp/iana"
"github.com/insomniacslk/dhcp/rfc1035label"
)
// WithTransactionID sets the Transaction ID for the DHCPv4 packet
func WithTransactionID(xid TransactionID) Modifier {
return func(d *DHCPv4) {
d.TransactionID = xid
}
}
// WithClientIP sets the Client IP for a DHCPv4 packet.
func WithClientIP(ip net.IP) Modifier {
return func(d *DHCPv4) {
d.ClientIPAddr = ip
}
}
// WithYourIP sets the Your IP for a DHCPv4 packet.
func WithYourIP(ip net.IP) Modifier {
return func(d *DHCPv4) {
d.YourIPAddr = ip
}
}
// WithServerIP sets the Server IP for a DHCPv4 packet.
func WithServerIP(ip net.IP) Modifier {
return func(d *DHCPv4) {
d.ServerIPAddr = ip
}
}
// WithGatewayIP sets the Gateway IP for the DHCPv4 packet.
func WithGatewayIP(ip net.IP) Modifier {
return func(d *DHCPv4) {
d.GatewayIPAddr = ip
}
}
// WithOptionCopied copies the value of option opt from request.
func WithOptionCopied(request *DHCPv4, opt OptionCode) Modifier {
return func(d *DHCPv4) {
if val := request.Options.Get(opt); val != nil {
d.UpdateOption(OptGeneric(opt, val))
}
}
}
// WithReply fills in opcode, hwtype, xid, clienthwaddr, and flags from the given packet.
func WithReply(request *DHCPv4) Modifier {
return func(d *DHCPv4) {
if request.OpCode == OpcodeBootRequest {
d.OpCode = OpcodeBootReply
} else {
d.OpCode = OpcodeBootRequest
}
d.HWType = request.HWType
d.TransactionID = request.TransactionID
d.ClientHWAddr = request.ClientHWAddr
d.Flags = request.Flags
}
}
// WithHWType sets the Hardware Type for a DHCPv4 packet.
func WithHWType(hwt iana.HWType) Modifier {
return func(d *DHCPv4) {
d.HWType = hwt
}
}
// WithBroadcast sets the packet to be broadcast or unicast
func WithBroadcast(broadcast bool) Modifier {
return func(d *DHCPv4) {
if broadcast {
d.SetBroadcast()
} else {
d.SetUnicast()
}
}
}
// WithHwAddr sets the hardware address for a packet
func WithHwAddr(hwaddr net.HardwareAddr) Modifier {
return func(d *DHCPv4) {
d.ClientHWAddr = hwaddr
}
}
// WithOption appends a DHCPv4 option provided by the user
func WithOption(opt Option) Modifier {
return func(d *DHCPv4) {
d.UpdateOption(opt)
}
}
// WithoutOption removes the DHCPv4 option with the given code
func WithoutOption(code OptionCode) Modifier {
return func(d *DHCPv4) {
d.DeleteOption(code)
}
}
// WithUserClass adds a user class option to the packet.
// The rfc parameter allows you to specify if the userclass should be
// rfc compliant or not. More details in issue #113
func WithUserClass(uc string, rfc bool) Modifier {
// TODO let the user specify multiple user classes
return func(d *DHCPv4) {
if rfc {
d.UpdateOption(OptRFC3004UserClass([]string{uc}))
} else {
d.UpdateOption(OptUserClass(uc))
}
}
}
// WithNetboot adds bootfile URL and bootfile param options to a DHCPv4 packet.
func WithNetboot(d *DHCPv4) {
WithRequestedOptions(OptionTFTPServerName, OptionBootfileName)(d)
}
// WithMessageType adds the DHCPv4 message type m to a packet.
func WithMessageType(m MessageType) Modifier {
return WithOption(OptMessageType(m))
}
// WithRequestedOptions adds requested options to the packet.
func WithRequestedOptions(optionCodes ...OptionCode) Modifier {
return func(d *DHCPv4) {
cl := d.ParameterRequestList()
cl.Add(optionCodes...)
d.UpdateOption(OptParameterRequestList(cl...))
}
}
// WithRelay adds parameters required for DHCPv4 to be relayed by the relay
// server with given ip
func WithRelay(ip net.IP) Modifier {
return func(d *DHCPv4) {
d.SetUnicast()
d.GatewayIPAddr = ip
d.HopCount++
}
}
// WithNetmask adds or updates an OptSubnetMask
func WithNetmask(mask net.IPMask) Modifier {
return WithOption(OptSubnetMask(mask))
}
// WithLeaseTime adds or updates an OptIPAddressLeaseTime
func WithLeaseTime(leaseTime uint32) Modifier {
return WithOption(OptIPAddressLeaseTime(time.Duration(leaseTime) * time.Second))
}
// WithDomainSearchList adds or updates an OptionDomainSearch
func WithDomainSearchList(searchList ...string) Modifier {
return WithOption(OptDomainSearch(&rfc1035label.Labels{
Labels: searchList,
}))
}
func WithGeneric(code OptionCode, value []byte) Modifier {
return WithOption(OptGeneric(code, value))
}

View File

@@ -0,0 +1,27 @@
package dhcpv4
import (
"fmt"
)
// OptionGeneric is an option that only contains the option code and associated
// data. Every option that does not have a specific implementation will fall
// back to this option.
type OptionGeneric struct {
Data []byte
}
// ToBytes returns a serialized generic option as a slice of bytes.
func (o OptionGeneric) ToBytes() []byte {
return o.Data
}
// String returns a human-readable representation of a generic option.
func (o OptionGeneric) String() string {
return fmt.Sprintf("%v", o.Data)
}
// OptGeneric returns a generic option.
func OptGeneric(code OptionCode, value []byte) Option {
return Option{Code: code, Value: OptionGeneric{value}}
}

View File

@@ -0,0 +1,62 @@
package dhcpv4
import (
"net"
"github.com/u-root/uio/uio"
)
// IP implements DHCPv4 IP option marshaling and unmarshaling as described by
// RFC 2132, Sections 5.3, 9.1, 9.7, and others.
type IP net.IP
// FromBytes parses an IP from data in binary form.
func (i *IP) FromBytes(data []byte) error {
buf := uio.NewBigEndianBuffer(data)
*i = IP(buf.CopyN(net.IPv4len))
return buf.FinError()
}
// ToBytes returns a serialized stream of bytes for this option.
func (i IP) ToBytes() []byte {
return []byte(net.IP(i).To4())
}
// String returns a human-readable IP.
func (i IP) String() string {
return net.IP(i).String()
}
// GetIP returns code out of o parsed as an IP.
func GetIP(code OptionCode, o Options) net.IP {
v := o.Get(code)
if v == nil {
return nil
}
var ip IP
if err := ip.FromBytes(v); err != nil {
return nil
}
return net.IP(ip)
}
// OptBroadcastAddress returns a new DHCPv4 Broadcast Address option.
//
// The broadcast address option is described in RFC 2132, Section 5.3.
func OptBroadcastAddress(ip net.IP) Option {
return Option{Code: OptionBroadcastAddress, Value: IP(ip)}
}
// OptRequestedIPAddress returns a new DHCPv4 Requested IP Address option.
//
// The requested IP address option is described by RFC 2132, Section 9.1.
func OptRequestedIPAddress(ip net.IP) Option {
return Option{Code: OptionRequestedIPAddress, Value: IP(ip)}
}
// OptServerIdentifier returns a new DHCPv4 Server Identifier option.
//
// The server identifier option is described by RFC 2132, Section 9.7.
func OptServerIdentifier(ip net.IP) Option {
return Option{Code: OptionServerIdentifier, Value: IP(ip)}
}

View File

@@ -0,0 +1,41 @@
package dhcpv4
import (
"math"
"time"
"github.com/u-root/uio/uio"
)
// MaxLeaseTime is the maximum lease time that can be encoded.
var MaxLeaseTime = math.MaxUint32 * time.Second
// Duration implements the IP address lease time option described by RFC 2132,
// Section 9.2.
type Duration time.Duration
// FromBytes parses a duration from a byte stream according to RFC 2132, Section 9.2.
func (d *Duration) FromBytes(data []byte) error {
buf := uio.NewBigEndianBuffer(data)
*d = Duration(time.Duration(buf.Read32()) * time.Second)
return buf.FinError()
}
// ToBytes returns a serialized stream of bytes for this option.
func (d Duration) ToBytes() []byte {
buf := uio.NewBigEndianBuffer(nil)
buf.Write32(uint32(time.Duration(d) / time.Second))
return buf.Data()
}
// String returns a human-readable string for this option.
func (d Duration) String() string {
return time.Duration(d).String()
}
// OptIPAddressLeaseTime returns a new IP address lease time option.
//
// The IP address lease time option is described by RFC 2132, Section 9.2.
func OptIPAddressLeaseTime(d time.Duration) Option {
return Option{Code: OptionIPAddressLeaseTime, Value: Duration(d)}
}

View File

@@ -0,0 +1,103 @@
package dhcpv4
import (
"fmt"
"net"
"strings"
"github.com/u-root/uio/uio"
)
// IPs are IPv4 addresses from a DHCP packet as used and specified by options
// in RFC 2132, Sections 3.5 through 3.13, 8.2, 8.3, 8.5, 8.6, 8.9, and 8.10.
//
// IPs implements the OptionValue type.
type IPs []net.IP
// FromBytes parses an IPv4 address from a DHCP packet as used and specified by
// options in RFC 2132, Sections 3.5 through 3.13, 8.2, 8.3, 8.5, 8.6, 8.9, and
// 8.10.
func (i *IPs) FromBytes(data []byte) error {
buf := uio.NewBigEndianBuffer(data)
if buf.Len() == 0 {
return fmt.Errorf("IP DHCP options must always list at least one IP")
}
*i = make(IPs, 0, buf.Len()/net.IPv4len)
for buf.Has(net.IPv4len) {
*i = append(*i, net.IP(buf.CopyN(net.IPv4len)))
}
return buf.FinError()
}
// ToBytes marshals IPv4 addresses to a DHCP packet as specified by RFC 2132,
// Section 3.5 et al.
func (i IPs) ToBytes() []byte {
buf := uio.NewBigEndianBuffer(nil)
for _, ip := range i {
buf.WriteBytes(ip.To4())
}
return buf.Data()
}
// String returns a human-readable representation of a list of IPs.
func (i IPs) String() string {
s := make([]string, 0, len(i))
for _, ip := range i {
s = append(s, ip.String())
}
return strings.Join(s, ", ")
}
// GetIPs parses a list of IPs from code in o.
func GetIPs(code OptionCode, o Options) []net.IP {
v := o.Get(code)
if v == nil {
return nil
}
var ips IPs
if err := ips.FromBytes(v); err != nil {
return nil
}
return []net.IP(ips)
}
// OptRouter returns a new DHCPv4 Router option.
//
// The Router option is described by RFC 2132, Section 3.5.
func OptRouter(routers ...net.IP) Option {
return Option{
Code: OptionRouter,
Value: IPs(routers),
}
}
// WithRouter updates a packet with the DHCPv4 Router option.
func WithRouter(routers ...net.IP) Modifier {
return WithOption(OptRouter(routers...))
}
// OptNTPServers returns a new DHCPv4 NTP Server option.
//
// The NTP servers option is described by RFC 2132, Section 8.3.
func OptNTPServers(ntpServers ...net.IP) Option {
return Option{
Code: OptionNTPServers,
Value: IPs(ntpServers),
}
}
// OptDNS returns a new DHCPv4 Domain Name Server option.
//
// The DNS server option is described by RFC 2132, Section 3.8.
func OptDNS(servers ...net.IP) Option {
return Option{
Code: OptionDomainNameServer,
Value: IPs(servers),
}
}
// WithDNS modifies a packet with the DHCPv4 Domain Name Server option.
func WithDNS(servers ...net.IP) Modifier {
return WithOption(OptDNS(servers...))
}

View File

@@ -0,0 +1,50 @@
package dhcpv4
import (
"fmt"
"github.com/u-root/uio/uio"
)
// Uint16 implements encoding and decoding functions for a uint16 as used in
// RFC 2132, Section 9.10.
type Uint16 uint16
// ToBytes returns a serialized stream of bytes for this option.
func (o Uint16) ToBytes() []byte {
buf := uio.NewBigEndianBuffer(nil)
buf.Write16(uint16(o))
return buf.Data()
}
// String returns a human-readable string for this option.
func (o Uint16) String() string {
return fmt.Sprintf("%d", uint16(o))
}
// FromBytes decodes data into o as per RFC 2132, Section 9.10.
func (o *Uint16) FromBytes(data []byte) error {
buf := uio.NewBigEndianBuffer(data)
*o = Uint16(buf.Read16())
return buf.FinError()
}
// GetUint16 parses a uint16 from code in o.
func GetUint16(code OptionCode, o Options) (uint16, error) {
v := o.Get(code)
if v == nil {
return 0, fmt.Errorf("option not present")
}
var u Uint16
if err := u.FromBytes(v); err != nil {
return 0, err
}
return uint16(u), nil
}
// OptMaxMessageSize returns a new DHCP Maximum Message Size option.
//
// The Maximum DHCP Message Size option is described by RFC 2132, Section 9.10.
func OptMaxMessageSize(size uint16) Option {
return Option{Code: OptionMaximumDHCPMessageSize, Value: Uint16(size)}
}

View File

@@ -0,0 +1,6 @@
package dhcpv4
// OptMessageType returns a new DHCPv4 Message Type option.
func OptMessageType(m MessageType) Option {
return Option{Code: OptionDHCPMessageType, Value: m}
}

View File

@@ -0,0 +1,23 @@
package dhcpv4
import (
"github.com/insomniacslk/dhcp/iana"
"github.com/insomniacslk/dhcp/rfc1035label"
)
// OptDomainSearch returns a new domain search option.
//
// The domain search option is described by RFC 3397, Section 2.
func OptDomainSearch(labels *rfc1035label.Labels) Option {
return Option{Code: OptionDNSDomainSearchList, Value: labels}
}
// OptClientArch returns a new Client System Architecture Type option.
func OptClientArch(archs ...iana.Arch) Option {
return Option{Code: OptionClientSystemArchitectureType, Value: iana.Archs(archs)}
}
// OptClientIdentifier returns a new Client Identifier option.
func OptClientIdentifier(ident []byte) Option {
return OptGeneric(OptionClientIdentifier, ident)
}

View File

@@ -0,0 +1,72 @@
package dhcpv4
import (
"sort"
"strings"
"github.com/u-root/uio/uio"
)
// OptionCodeList is a list of DHCP option codes.
type OptionCodeList []OptionCode
// Has returns whether c is in the list.
func (ol OptionCodeList) Has(c OptionCode) bool {
for _, code := range ol {
if code == c {
return true
}
}
return false
}
// Add adds option codes in cs to ol.
func (ol *OptionCodeList) Add(cs ...OptionCode) {
for _, c := range cs {
if !ol.Has(c) {
*ol = append(*ol, c)
}
}
}
func (ol OptionCodeList) sort() {
sort.Slice(ol, func(i, j int) bool { return ol[i].Code() < ol[j].Code() })
}
// String returns a human-readable string for the option names.
func (ol OptionCodeList) String() string {
var names []string
ol.sort()
for _, code := range ol {
names = append(names, code.String())
}
return strings.Join(names, ", ")
}
// ToBytes returns a serialized stream of bytes for this option as defined by
// RFC 2132, Section 9.8.
func (ol OptionCodeList) ToBytes() []byte {
buf := uio.NewBigEndianBuffer(nil)
for _, req := range ol {
buf.Write8(req.Code())
}
return buf.Data()
}
// FromBytes parses a byte stream for this option as described by RFC 2132,
// Section 9.8.
func (ol *OptionCodeList) FromBytes(data []byte) error {
buf := uio.NewBigEndianBuffer(data)
*ol = make(OptionCodeList, 0, buf.Len())
for buf.Has(1) {
*ol = append(*ol, optionCode(buf.Read8()))
}
return buf.FinError()
}
// OptParameterRequestList returns a new DHCPv4 Parameter Request List.
//
// The parameter request list option is described by RFC 2132, Section 9.8.
func OptParameterRequestList(codes ...OptionCode) Option {
return Option{Code: OptionParameterRequestList, Value: OptionCodeList(codes)}
}

View File

@@ -0,0 +1,92 @@
package dhcpv4
import (
"fmt"
)
// RelayOptions is like Options, but stringifies using the Relay Agent Specific
// option space.
type RelayOptions struct {
Options
}
var relayHumanizer = OptionHumanizer{
ValueHumanizer: func(code OptionCode, data []byte) fmt.Stringer {
return raiSubOptionValue{data}
},
CodeHumanizer: func(c uint8) OptionCode {
return raiSubOptionCode(c)
},
}
// String prints the contained options using Relay Agent-specific option code parsing.
func (r RelayOptions) String() string {
return "\n" + r.Options.ToString(relayHumanizer)
}
// FromBytes parses relay agent options from data.
func (r *RelayOptions) FromBytes(data []byte) error {
r.Options = make(Options)
return r.Options.FromBytes(data)
}
// OptRelayAgentInfo returns a new DHCP Relay Agent Info option.
//
// The relay agent info option is described by RFC 3046.
func OptRelayAgentInfo(o ...Option) Option {
return Option{Code: OptionRelayAgentInformation, Value: RelayOptions{OptionsFromList(o...)}}
}
type raiSubOptionValue struct {
val []byte
}
func (rv raiSubOptionValue) String() string {
return fmt.Sprintf("%s (%v)", string(rv.val), rv.val)
}
type raiSubOptionCode uint8
func (o raiSubOptionCode) Code() uint8 {
return uint8(o)
}
func (o raiSubOptionCode) String() string {
if s, ok := raiSubOptionCodeToString[o]; ok {
return s
}
return fmt.Sprintf("unknown (%d)", o)
}
// Option 82 Relay Agention Information Sub Options
const (
AgentCircuitIDSubOption raiSubOptionCode = 1 // RFC 3046
AgentRemoteIDSubOption raiSubOptionCode = 2 // RFC 3046
DOCSISDeviceClassSubOption raiSubOptionCode = 4 // RFC 3256
LinkSelectionSubOption raiSubOptionCode = 5 // RFC 3527
SubscriberIDSubOption raiSubOptionCode = 6 // RFC 3993
RADIUSAttributesSubOption raiSubOptionCode = 7 // RFC 4014
AuthenticationSubOption raiSubOptionCode = 8 // RFC 4030
VendorSpecificInformationSubOption raiSubOptionCode = 9 // RFC 4243
RelayAgentFlagsSubOption raiSubOptionCode = 10 // RFC 5010
ServerIdentifierOverrideSubOption raiSubOptionCode = 11 // RFC 5107
RelaySourcePortSubOption raiSubOptionCode = 19 // RFC 8357
VirtualSubnetSelectionSubOption raiSubOptionCode = 151 // RFC 6607
VirtualSubnetSelectionControlSubOption raiSubOptionCode = 152 // RFC 6607
)
var raiSubOptionCodeToString = map[raiSubOptionCode]string{
AgentCircuitIDSubOption: "Agent Circuit ID Sub-option",
AgentRemoteIDSubOption: "Agent Remote ID Sub-option",
DOCSISDeviceClassSubOption: "DOCSIS Device Class Sub-option",
LinkSelectionSubOption: "Link Selection Sub-option",
SubscriberIDSubOption: "Subscriber ID Sub-option",
RADIUSAttributesSubOption: "RADIUS Attributes Sub-option",
AuthenticationSubOption: "Authentication Sub-option",
VendorSpecificInformationSubOption: "Vendor Specific Sub-option",
RelayAgentFlagsSubOption: "Relay Agent Flags Sub-option",
ServerIdentifierOverrideSubOption: "Server Identifier Override Sub-option",
RelaySourcePortSubOption: "Relay Source Port Sub-option",
VirtualSubnetSelectionSubOption: "Virtual Subnet Selection Sub-option",
VirtualSubnetSelectionControlSubOption: "Virtual Subnet Selection Control Sub-option",
}

View File

@@ -0,0 +1,104 @@
package dhcpv4
import (
"fmt"
"net"
"strings"
"github.com/u-root/uio/uio"
)
// Route is a classless static route as per RFC 3442.
type Route struct {
// Dest is the destination network.
Dest *net.IPNet
// Router is the router to use for the given destination network.
Router net.IP
}
// Marshal implements uio.Marshaler.
//
// Format described in RFC 3442:
//
// <size of mask in number of bits>
// <destination address, omitting octets that must be zero per mask>
// <route IP>
func (r Route) Marshal(buf *uio.Lexer) {
ones, _ := r.Dest.Mask.Size()
buf.Write8(uint8(ones))
// Only write the non-zero octets.
dstLen := (ones + 7) / 8
buf.WriteBytes(r.Dest.IP.To4()[:dstLen])
buf.WriteBytes(r.Router.To4())
}
// Unmarshal implements uio.Unmarshaler.
func (r *Route) Unmarshal(buf *uio.Lexer) error {
maskSize := buf.Read8()
if maskSize > 32 {
return fmt.Errorf("invalid mask length %d in route option", maskSize)
}
r.Dest = &net.IPNet{
IP: make([]byte, net.IPv4len),
Mask: net.CIDRMask(int(maskSize), 32),
}
dstLen := (maskSize + 7) / 8
buf.ReadBytes(r.Dest.IP[:dstLen])
r.Router = buf.CopyN(net.IPv4len)
return buf.Error()
}
// String prints the destination network and router IP.
func (r *Route) String() string {
return fmt.Sprintf("route to %s via %s", r.Dest, r.Router)
}
// Routes is a collection of network routes.
type Routes []*Route
// FromBytes parses routes from a set of bytes as described by RFC 3442.
func (r *Routes) FromBytes(p []byte) error {
buf := uio.NewBigEndianBuffer(p)
for buf.Has(1) {
var route Route
if err := route.Unmarshal(buf); err != nil {
return err
}
*r = append(*r, &route)
}
return buf.FinError()
}
// ToBytes marshals a set of routes as described by RFC 3442.
func (r Routes) ToBytes() []byte {
buf := uio.NewBigEndianBuffer(nil)
for _, route := range r {
route.Marshal(buf)
}
return buf.Data()
}
// String prints all routes.
func (r Routes) String() string {
s := make([]string, 0, len(r))
for _, route := range r {
s = append(s, route.String())
}
return strings.Join(s, "; ")
}
// OptClasslessStaticRoute returns a new DHCPv4 Classless Static Route
// option.
//
// The Classless Static Route option is described by RFC 3442.
func OptClasslessStaticRoute(routes ...*Route) Option {
return Option{
Code: OptionClasslessStaticRoute,
Value: Routes(routes),
}
}

View File

@@ -0,0 +1,84 @@
package dhcpv4
// String represents an option encapsulating a string in IPv4 DHCP.
//
// This representation is shared by multiple options specified by RFC 2132,
// Sections 3.14, 3.16, 3.17, 3.19, and 3.20.
type String string
// ToBytes returns a serialized stream of bytes for this option.
func (o String) ToBytes() []byte {
return []byte(o)
}
// String returns a human-readable string.
func (o String) String() string {
return string(o)
}
// FromBytes parses a serialized stream of bytes into o.
func (o *String) FromBytes(data []byte) error {
*o = String(string(data))
return nil
}
// GetString parses an RFC 2132 string from o[code].
func GetString(code OptionCode, o Options) string {
v := o.Get(code)
if v == nil {
return ""
}
return string(v)
}
// OptDomainName returns a new DHCPv4 Domain Name option.
//
// The Domain Name option is described by RFC 2132, Section 3.17.
func OptDomainName(name string) Option {
return Option{Code: OptionDomainName, Value: String(name)}
}
// OptHostName returns a new DHCPv4 Host Name option.
//
// The Host Name option is described by RFC 2132, Section 3.14.
func OptHostName(name string) Option {
return Option{Code: OptionHostName, Value: String(name)}
}
// OptRootPath returns a new DHCPv4 Root Path option.
//
// The Root Path option is described by RFC 2132, Section 3.19.
func OptRootPath(name string) Option {
return Option{Code: OptionRootPath, Value: String(name)}
}
// OptBootFileName returns a new DHCPv4 Boot File Name option.
//
// The Bootfile Name option is described by RFC 2132, Section 9.5.
func OptBootFileName(name string) Option {
return Option{Code: OptionBootfileName, Value: String(name)}
}
// OptTFTPServerName returns a new DHCPv4 TFTP Server Name option.
//
// The TFTP Server Name option is described by RFC 2132, Section 9.4.
func OptTFTPServerName(name string) Option {
return Option{Code: OptionTFTPServerName, Value: String(name)}
}
// OptClassIdentifier returns a new DHCPv4 Class Identifier option.
//
// The Vendor Class Identifier option is described by RFC 2132, Section 9.13.
func OptClassIdentifier(name string) Option {
return Option{Code: OptionClassIdentifier, Value: String(name)}
}
// OptUserClass returns a new DHCPv4 User Class option.
func OptUserClass(name string) Option {
return Option{Code: OptionUserClassInformation, Value: String(name)}
}
// OptMessage returns a new DHCPv4 (Error) Message option.
func OptMessage(msg string) Option {
return Option{Code: OptionMessage, Value: String(msg)}
}

View File

@@ -0,0 +1,55 @@
package dhcpv4
import (
"fmt"
"strings"
"github.com/u-root/uio/uio"
)
// Strings represents an option encapsulating a list of strings in IPv4 DHCP as
// specified in RFC 3004
//
// Strings implements the OptionValue type.
type Strings []string
// FromBytes parses Strings from a DHCP packet as specified by RFC 3004.
func (o *Strings) FromBytes(data []byte) error {
buf := uio.NewBigEndianBuffer(data)
if buf.Len() == 0 {
return fmt.Errorf("Strings DHCP option must always list at least one String")
}
*o = make(Strings, 0)
for buf.Has(1) {
ucLen := buf.Read8()
if ucLen == 0 {
return fmt.Errorf("DHCP Strings must have length greater than 0")
}
*o = append(*o, string(buf.CopyN(int(ucLen))))
}
return buf.FinError()
}
// ToBytes marshals Strings to a DHCP packet as specified by RFC 3004.
func (o Strings) ToBytes() []byte {
buf := uio.NewBigEndianBuffer(nil)
for _, uc := range o {
buf.Write8(uint8(len(uc)))
buf.WriteBytes([]byte(uc))
}
return buf.Data()
}
// String returns a human-readable representation of a list of Strings.
func (o Strings) String() string {
return strings.Join(o, ", ")
}
// OptRFC3004UserClass returns a new user class option according to RFC 3004.
func OptRFC3004UserClass(v []string) Option {
return Option{
Code: OptionUserClassInformation,
Value: Strings(v),
}
}

View File

@@ -0,0 +1,40 @@
package dhcpv4
import (
"net"
"github.com/u-root/uio/uio"
)
// IPMask represents an option encapsulating the subnet mask.
//
// This option implements the subnet mask option in RFC 2132, Section 3.3.
type IPMask net.IPMask
// ToBytes returns a serialized stream of bytes for this option.
func (im IPMask) ToBytes() []byte {
if len(im) > net.IPv4len {
return im[:net.IPv4len]
}
return im
}
// String returns a human-readable string.
func (im IPMask) String() string {
return net.IPMask(im).String()
}
// FromBytes parses im from data per RFC 2132.
func (im *IPMask) FromBytes(data []byte) error {
buf := uio.NewBigEndianBuffer(data)
*im = IPMask(buf.CopyN(net.IPv4len))
return buf.FinError()
}
// OptSubnetMask returns a new DHCPv4 SubnetMask option per RFC 2132, Section 3.3.
func OptSubnetMask(mask net.IPMask) Option {
return Option{
Code: OptionSubnetMask,
Value: IPMask(mask),
}
}

View File

@@ -0,0 +1,65 @@
package dhcpv4
import (
"bytes"
"fmt"
"github.com/insomniacslk/dhcp/iana"
"github.com/u-root/uio/uio"
)
// VIVCIdentifier implements the vendor-identifying vendor class option
// described by RFC 3925.
type VIVCIdentifier struct {
// EntID is the enterprise ID.
EntID iana.EnterpriseID
Data []byte
}
// OptVIVC returns a new vendor-identifying vendor class option.
//
// The option is described by RFC 3925.
func OptVIVC(identifiers ...VIVCIdentifier) Option {
return Option{
Code: OptionVendorIdentifyingVendorClass,
Value: VIVCIdentifiers(identifiers),
}
}
// VIVCIdentifiers implements encoding and decoding methods for a DHCP option
// described in RFC 3925.
type VIVCIdentifiers []VIVCIdentifier
// FromBytes parses data into ids per RFC 3925.
func (ids *VIVCIdentifiers) FromBytes(data []byte) error {
buf := uio.NewBigEndianBuffer(data)
for buf.Has(5) {
entID := iana.EnterpriseID(buf.Read32())
idLen := int(buf.Read8())
*ids = append(*ids, VIVCIdentifier{EntID: entID, Data: buf.CopyN(idLen)})
}
return buf.FinError()
}
// ToBytes returns a serialized stream of bytes for this option.
func (ids VIVCIdentifiers) ToBytes() []byte {
buf := uio.NewBigEndianBuffer(nil)
for _, id := range ids {
buf.Write32(uint32(id.EntID))
buf.Write8(uint8(len(id.Data)))
buf.WriteBytes(id.Data)
}
return buf.Data()
}
// String returns a human-readable string for this option.
func (ids VIVCIdentifiers) String() string {
if len(ids) == 0 {
return ""
}
buf := bytes.Buffer{}
for _, id := range ids {
fmt.Fprintf(&buf, " %d:'%s',", id.EntID, id.Data)
}
return buf.String()[1 : buf.Len()-1]
}

368
vendor/github.com/insomniacslk/dhcp/dhcpv4/options.go generated vendored Normal file
View File

@@ -0,0 +1,368 @@
package dhcpv4
import (
"errors"
"fmt"
"io"
"math"
"sort"
"strings"
"github.com/insomniacslk/dhcp/iana"
"github.com/insomniacslk/dhcp/rfc1035label"
"github.com/u-root/uio/uio"
)
var (
// ErrShortByteStream is an error that is thrown any time a short byte stream is
// detected during option parsing.
ErrShortByteStream = errors.New("short byte stream")
// ErrZeroLengthByteStream is an error that is thrown any time a zero-length
// byte stream is encountered.
ErrZeroLengthByteStream = errors.New("zero-length byte stream")
// ErrInvalidOptions is returned when invalid options data is
// encountered during parsing. The data could report an incorrect
// length or have trailing bytes which are not part of the option.
ErrInvalidOptions = errors.New("invalid options data")
)
// OptionValue is an interface that all DHCP v4 options adhere to.
type OptionValue interface {
ToBytes() []byte
String() string
}
// Option is a DHCPv4 option and consists of a 1-byte option code and a value
// stream of bytes.
//
// The value is to be interpreted based on the option code.
type Option struct {
Code OptionCode
Value OptionValue
}
// String returns a human-readable version of this option.
func (o Option) String() string {
v := o.Value.String()
if strings.Contains(v, "\n") {
return fmt.Sprintf("%s:\n%s", o.Code, v)
}
return fmt.Sprintf("%s: %s", o.Code, v)
}
// Options is a collection of options.
type Options map[uint8][]byte
// OptionsFromList adds all given options to an options map.
func OptionsFromList(o ...Option) Options {
opts := make(Options)
for _, opt := range o {
opts.Update(opt)
}
return opts
}
// Get will attempt to get all options that match a DHCPv4 option
// from its OptionCode. If the option was not found it will return an
// empty list.
//
// According to RFC 3396, options that are specified more than once are
// concatenated, and hence this should always just return one option. This
// currently returns a list to be API compatible.
func (o Options) Get(code OptionCode) []byte {
return o[code.Code()]
}
// Has checks whether o has the given opcode.
func (o Options) Has(opcode OptionCode) bool {
_, ok := o[opcode.Code()]
return ok
}
// Del deletes the option matching the option code.
func (o Options) Del(opcode OptionCode) {
delete(o, opcode.Code())
}
// Update updates the existing options with the passed option, adding it
// at the end if not present already
func (o Options) Update(option Option) {
o[option.Code.Code()] = option.Value.ToBytes()
}
// ToBytes makes Options usable as an OptionValue as well.
//
// Used in the case of vendor-specific and relay agent options.
func (o Options) ToBytes() []byte {
return uio.ToBigEndian(o)
}
// FromBytes parses a sequence of bytes until the end and builds a list of
// options from it.
//
// The sequence should not contain the DHCP magic cookie.
//
// Returns an error if any invalid option or length is found.
func (o Options) FromBytes(data []byte) error {
return o.fromBytesCheckEnd(data, false)
}
const (
optPad = 0
optEnd = 255
)
// FromBytesCheckEnd parses Options from byte sequences using the
// parsing function that is passed in as a paremeter
func (o Options) fromBytesCheckEnd(data []byte, checkEndOption bool) error {
if len(data) == 0 {
return nil
}
buf := uio.NewBigEndianBuffer(data)
var end bool
for buf.Len() >= 1 {
// 1 byte: option code
// 1 byte: option length n
// n bytes: data
code := buf.Read8()
if code == optPad {
continue
} else if code == optEnd {
end = true
break
}
length := int(buf.Read8())
// N bytes: option data
data := buf.Consume(length)
if data == nil {
return fmt.Errorf("error collecting options: %v", buf.Error())
}
data = data[:length:length]
// RFC 2131, Section 4.1 "Options may appear only once, [...].
// The client concatenates the values of multiple instances of
// the same option into a single parameter list for
// configuration."
//
// See also RFC 3396 for concatenation order and options longer
// than 255 bytes.
o[code] = append(o[code], data...)
}
// If we never read the End option, the sender of this packet screwed
// up.
if !end && checkEndOption {
return io.ErrUnexpectedEOF
}
// Any bytes left must be padding.
var pad uint8
for buf.Len() >= 1 {
pad = buf.Read8()
if pad != optPad && pad != optEnd {
return ErrInvalidOptions
}
}
return nil
}
// sortedKeys returns an ordered slice of option keys from the Options map, for
// use in serializing options to binary.
func (o Options) sortedKeys() []int {
// Send all values for a given key
var codes []int
for k := range o {
codes = append(codes, int(k))
}
sort.Ints(codes)
return codes
}
// Marshal writes options binary representations to b.
func (o Options) Marshal(b *uio.Lexer) {
for _, c := range o.sortedKeys() {
code := uint8(c)
// Even if the End option is in there, don't marshal it until
// the end.
// Don't write padding either, since the options are sorted
// it would always be written first which isn't useful
if code == optEnd || code == optPad {
continue
}
data := o[code]
// Ensure even 0-length options are written out
if len(data) == 0 {
b.Write8(code)
b.Write8(0)
continue
}
// RFC 3396: If more than 256 bytes of data are given, the
// option is simply listed multiple times.
for len(data) > 0 {
// 1 byte: option code
b.Write8(code)
n := len(data)
if n > math.MaxUint8 {
n = math.MaxUint8
}
// 1 byte: option length
b.Write8(uint8(n))
// N bytes: option data
b.WriteBytes(data[:n])
data = data[n:]
}
}
}
// String prints options using DHCP-specified option codes.
func (o Options) String() string {
return o.ToString(dhcpHumanizer)
}
// Summary prints options in human-readable values.
//
// Summary uses vendorParser to interpret the OptionVendorSpecificInformation option.
func (o Options) Summary(vendorDecoder OptionDecoder) string {
return o.ToString(OptionHumanizer{
ValueHumanizer: parserFor(vendorDecoder),
CodeHumanizer: func(c uint8) OptionCode {
return optionCode(c)
},
})
}
// OptionParser gives a human-legible interpretation of data for the given option code.
type OptionParser func(code OptionCode, data []byte) fmt.Stringer
// OptionHumanizer is used to interpret a set of Options for their option code
// name and values.
//
// There should be separate OptionHumanizers for each Option "space": DHCP,
// BSDP, Relay Agent Info, and others.
type OptionHumanizer struct {
ValueHumanizer OptionParser
CodeHumanizer func(code uint8) OptionCode
}
// Stringify returns a human-readable interpretation of the option code and its
// associated data.
func (oh OptionHumanizer) Stringify(code uint8, data []byte) string {
c := oh.CodeHumanizer(code)
val := oh.ValueHumanizer(c, data)
return fmt.Sprintf("%s: %s", c, val)
}
// dhcpHumanizer humanizes the set of DHCP option codes.
var dhcpHumanizer = OptionHumanizer{
ValueHumanizer: parseOption,
CodeHumanizer: func(c uint8) OptionCode {
return optionCode(c)
},
}
// ToString uses parse to parse options into human-readable values.
func (o Options) ToString(humanizer OptionHumanizer) string {
var ret string
for _, c := range o.sortedKeys() {
code := uint8(c)
v := o[code]
optString := humanizer.Stringify(code, v)
// If this option has sub structures, offset them accordingly.
if strings.Contains(optString, "\n") {
optString = strings.Replace(optString, "\n ", "\n ", -1)
}
ret += fmt.Sprintf(" %v\n", optString)
}
return ret
}
func parseOption(code OptionCode, data []byte) fmt.Stringer {
return parserFor(nil)(code, data)
}
func parserFor(vendorParser OptionDecoder) OptionParser {
return func(code OptionCode, data []byte) fmt.Stringer {
return getOption(code, data, vendorParser)
}
}
// OptionDecoder can decode a byte stream into a human-readable option.
type OptionDecoder interface {
fmt.Stringer
FromBytes([]byte) error
}
func getOption(code OptionCode, data []byte, vendorDecoder OptionDecoder) fmt.Stringer {
var d OptionDecoder
switch code {
case OptionRouter, OptionDomainNameServer, OptionNTPServers, OptionServerIdentifier:
d = &IPs{}
case OptionBroadcastAddress, OptionRequestedIPAddress:
d = &IP{}
case OptionClientSystemArchitectureType:
d = &iana.Archs{}
case OptionSubnetMask:
d = &IPMask{}
case OptionDHCPMessageType:
var mt MessageType
d = &mt
case OptionParameterRequestList:
d = &OptionCodeList{}
case OptionHostName, OptionDomainName, OptionRootPath,
OptionClassIdentifier, OptionTFTPServerName, OptionBootfileName:
var s String
d = &s
case OptionRelayAgentInformation:
d = &RelayOptions{}
case OptionDNSDomainSearchList:
d = &rfc1035label.Labels{}
case OptionIPAddressLeaseTime:
var dur Duration
d = &dur
case OptionMaximumDHCPMessageSize:
var u Uint16
d = &u
case OptionUserClassInformation:
var s Strings
d = &s
if s.FromBytes(data) != nil {
var s String
d = &s
}
case OptionVendorIdentifyingVendorClass:
d = &VIVCIdentifiers{}
case OptionVendorSpecificInformation:
d = vendorDecoder
case OptionClasslessStaticRoute:
d = &Routes{}
}
if d != nil && d.FromBytes(data) == nil {
return d
}
return OptionGeneric{data}
}

463
vendor/github.com/insomniacslk/dhcp/dhcpv4/types.go generated vendored Normal file
View File

@@ -0,0 +1,463 @@
package dhcpv4
import (
"fmt"
"github.com/u-root/uio/uio"
)
// values from http://www.networksorcery.com/enp/protocol/dhcp.htm and
// http://www.networksorcery.com/enp/protocol/bootp/options.htm
// TransactionID represents a 4-byte DHCP transaction ID as defined in RFC 951,
// Section 3.
//
// The TransactionID is used to match DHCP replies to their original request.
type TransactionID [4]byte
// String prints a hex transaction ID.
func (xid TransactionID) String() string {
return fmt.Sprintf("0x%x", xid[:])
}
// MessageType represents the possible DHCP message types - DISCOVER, OFFER, etc
type MessageType byte
// DHCP message types
const (
// MessageTypeNone is not a real message type, it is used by certain
// functions to signal that no explicit message type is requested
MessageTypeNone MessageType = 0
MessageTypeDiscover MessageType = 1
MessageTypeOffer MessageType = 2
MessageTypeRequest MessageType = 3
MessageTypeDecline MessageType = 4
MessageTypeAck MessageType = 5
MessageTypeNak MessageType = 6
MessageTypeRelease MessageType = 7
MessageTypeInform MessageType = 8
)
// ToBytes returns the serialized version of this option described by RFC 2132,
// Section 9.6.
func (m MessageType) ToBytes() []byte {
return []byte{byte(m)}
}
// String prints a human-readable message type name.
func (m MessageType) String() string {
if s, ok := messageTypeToString[m]; ok {
return s
}
return fmt.Sprintf("unknown (%d)", byte(m))
}
// FromBytes reads a message type from data as described by RFC 2132, Section
// 9.6.
func (m *MessageType) FromBytes(data []byte) error {
buf := uio.NewBigEndianBuffer(data)
*m = MessageType(buf.Read8())
return buf.FinError()
}
var messageTypeToString = map[MessageType]string{
MessageTypeDiscover: "DISCOVER",
MessageTypeOffer: "OFFER",
MessageTypeRequest: "REQUEST",
MessageTypeDecline: "DECLINE",
MessageTypeAck: "ACK",
MessageTypeNak: "NAK",
MessageTypeRelease: "RELEASE",
MessageTypeInform: "INFORM",
}
// OpcodeType represents a DHCPv4 opcode.
type OpcodeType uint8
// constants that represent valid values for OpcodeType
const (
OpcodeBootRequest OpcodeType = 1
OpcodeBootReply OpcodeType = 2
)
func (o OpcodeType) String() string {
if s, ok := opcodeToString[o]; ok {
return s
}
return fmt.Sprintf("unknown (%d)", uint8(o))
}
var opcodeToString = map[OpcodeType]string{
OpcodeBootRequest: "BootRequest",
OpcodeBootReply: "BootReply",
}
// OptionCode is a single byte representing the code for a given Option.
//
// OptionCode is an interface purely to support different stringers on options
// with the same Code value, as vendor-specific options use option codes that
// have the same value, but mean a different thing.
type OptionCode interface {
// Code is the 1 byte option code for the wire.
Code() uint8
// String returns the option's name.
String() string
}
// optionCode is a DHCP option code.
type optionCode uint8
// Code implements OptionCode.Code.
func (o optionCode) Code() uint8 {
return uint8(o)
}
// String returns an option name.
func (o optionCode) String() string {
if s, ok := optionCodeToString[o]; ok {
return s
}
return fmt.Sprintf("unknown (%d)", uint8(o))
}
// GenericOptionCode is an unnamed option code.
type GenericOptionCode uint8
// Code implements OptionCode.Code.
func (o GenericOptionCode) Code() uint8 {
return uint8(o)
}
// String returns the option's name.
func (o GenericOptionCode) String() string {
return fmt.Sprintf("unknown (%d)", uint8(o))
}
// DHCPv4 Options
const (
OptionPad optionCode = 0
OptionSubnetMask optionCode = 1
OptionTimeOffset optionCode = 2
OptionRouter optionCode = 3
OptionTimeServer optionCode = 4
OptionNameServer optionCode = 5
OptionDomainNameServer optionCode = 6
OptionLogServer optionCode = 7
OptionQuoteServer optionCode = 8
OptionLPRServer optionCode = 9
OptionImpressServer optionCode = 10
OptionResourceLocationServer optionCode = 11
OptionHostName optionCode = 12
OptionBootFileSize optionCode = 13
OptionMeritDumpFile optionCode = 14
OptionDomainName optionCode = 15
OptionSwapServer optionCode = 16
OptionRootPath optionCode = 17
OptionExtensionsPath optionCode = 18
OptionIPForwarding optionCode = 19
OptionNonLocalSourceRouting optionCode = 20
OptionPolicyFilter optionCode = 21
OptionMaximumDatagramAssemblySize optionCode = 22
OptionDefaultIPTTL optionCode = 23
OptionPathMTUAgingTimeout optionCode = 24
OptionPathMTUPlateauTable optionCode = 25
OptionInterfaceMTU optionCode = 26
OptionAllSubnetsAreLocal optionCode = 27
OptionBroadcastAddress optionCode = 28
OptionPerformMaskDiscovery optionCode = 29
OptionMaskSupplier optionCode = 30
OptionPerformRouterDiscovery optionCode = 31
OptionRouterSolicitationAddress optionCode = 32
OptionStaticRoutingTable optionCode = 33
OptionTrailerEncapsulation optionCode = 34
OptionArpCacheTimeout optionCode = 35
OptionEthernetEncapsulation optionCode = 36
OptionDefaulTCPTTL optionCode = 37
OptionTCPKeepaliveInterval optionCode = 38
OptionTCPKeepaliveGarbage optionCode = 39
OptionNetworkInformationServiceDomain optionCode = 40
OptionNetworkInformationServers optionCode = 41
OptionNTPServers optionCode = 42
OptionVendorSpecificInformation optionCode = 43
OptionNetBIOSOverTCPIPNameServer optionCode = 44
OptionNetBIOSOverTCPIPDatagramDistributionServer optionCode = 45
OptionNetBIOSOverTCPIPNodeType optionCode = 46
OptionNetBIOSOverTCPIPScope optionCode = 47
OptionXWindowSystemFontServer optionCode = 48
OptionXWindowSystemDisplayManger optionCode = 49
OptionRequestedIPAddress optionCode = 50
OptionIPAddressLeaseTime optionCode = 51
OptionOptionOverload optionCode = 52
OptionDHCPMessageType optionCode = 53
OptionServerIdentifier optionCode = 54
OptionParameterRequestList optionCode = 55
OptionMessage optionCode = 56
OptionMaximumDHCPMessageSize optionCode = 57
OptionRenewTimeValue optionCode = 58
OptionRebindingTimeValue optionCode = 59
OptionClassIdentifier optionCode = 60
OptionClientIdentifier optionCode = 61
OptionNetWareIPDomainName optionCode = 62
OptionNetWareIPInformation optionCode = 63
OptionNetworkInformationServicePlusDomain optionCode = 64
OptionNetworkInformationServicePlusServers optionCode = 65
OptionTFTPServerName optionCode = 66
OptionBootfileName optionCode = 67
OptionMobileIPHomeAgent optionCode = 68
OptionSimpleMailTransportProtocolServer optionCode = 69
OptionPostOfficeProtocolServer optionCode = 70
OptionNetworkNewsTransportProtocolServer optionCode = 71
OptionDefaultWorldWideWebServer optionCode = 72
OptionDefaultFingerServer optionCode = 73
OptionDefaultInternetRelayChatServer optionCode = 74
OptionStreetTalkServer optionCode = 75
OptionStreetTalkDirectoryAssistanceServer optionCode = 76
OptionUserClassInformation optionCode = 77
OptionSLPDirectoryAgent optionCode = 78
OptionSLPServiceScope optionCode = 79
OptionRapidCommit optionCode = 80
OptionFQDN optionCode = 81
OptionRelayAgentInformation optionCode = 82
OptionInternetStorageNameService optionCode = 83
// Option 84 returned in RFC 3679
OptionNDSServers optionCode = 85
OptionNDSTreeName optionCode = 86
OptionNDSContext optionCode = 87
OptionBCMCSControllerDomainNameList optionCode = 88
OptionBCMCSControllerIPv4AddressList optionCode = 89
OptionAuthentication optionCode = 90
OptionClientLastTransactionTime optionCode = 91
OptionAssociatedIP optionCode = 92
OptionClientSystemArchitectureType optionCode = 93
OptionClientNetworkInterfaceIdentifier optionCode = 94
OptionLDAP optionCode = 95
// Option 96 returned in RFC 3679
OptionClientMachineIdentifier optionCode = 97
OptionOpenGroupUserAuthentication optionCode = 98
OptionGeoConfCivic optionCode = 99
OptionIEEE10031TZString optionCode = 100
OptionReferenceToTZDatabase optionCode = 101
// Options 102-111 returned in RFC 3679
OptionNetInfoParentServerAddress optionCode = 112
OptionNetInfoParentServerTag optionCode = 113
OptionURL optionCode = 114
// Option 115 returned in RFC 3679
OptionAutoConfigure optionCode = 116
OptionNameServiceSearch optionCode = 117
OptionSubnetSelection optionCode = 118
OptionDNSDomainSearchList optionCode = 119
OptionSIPServers optionCode = 120
OptionClasslessStaticRoute optionCode = 121
OptionCCC optionCode = 122
OptionGeoConf optionCode = 123
OptionVendorIdentifyingVendorClass optionCode = 124
OptionVendorIdentifyingVendorSpecific optionCode = 125
// Options 126-127 returned in RFC 3679
OptionTFTPServerIPAddress optionCode = 128
OptionCallServerIPAddress optionCode = 129
OptionDiscriminationString optionCode = 130
OptionRemoteStatisticsServerIPAddress optionCode = 131
Option8021PVLANID optionCode = 132
Option8021QL2Priority optionCode = 133
OptionDiffservCodePoint optionCode = 134
OptionHTTPProxyForPhoneSpecificApplications optionCode = 135
OptionPANAAuthenticationAgent optionCode = 136
OptionLoSTServer optionCode = 137
OptionCAPWAPAccessControllerAddresses optionCode = 138
OptionOPTIONIPv4AddressMoS optionCode = 139
OptionOPTIONIPv4FQDNMoS optionCode = 140
OptionSIPUAConfigurationServiceDomains optionCode = 141
OptionOPTIONIPv4AddressANDSF optionCode = 142
OptionOPTIONIPv6AddressANDSF optionCode = 143
// Options 144-149 returned in RFC 3679
OptionTFTPServerAddress optionCode = 150
OptionStatusCode optionCode = 151
OptionBaseTime optionCode = 152
OptionStartTimeOfState optionCode = 153
OptionQueryStartTime optionCode = 154
OptionQueryEndTime optionCode = 155
OptionDHCPState optionCode = 156
OptionDataSource optionCode = 157
// Options 158-174 returned in RFC 3679
OptionEtherboot optionCode = 175
OptionIPTelephone optionCode = 176
OptionEtherbootPacketCableAndCableHome optionCode = 177
// Options 178-207 returned in RFC 3679
OptionPXELinuxMagicString optionCode = 208
OptionPXELinuxConfigFile optionCode = 209
OptionPXELinuxPathPrefix optionCode = 210
OptionPXELinuxRebootTime optionCode = 211
OptionOPTION6RD optionCode = 212
OptionOPTIONv4AccessDomain optionCode = 213
// Options 214-219 returned in RFC 3679
OptionSubnetAllocation optionCode = 220
OptionVirtualSubnetAllocation optionCode = 221
// Options 222-223 returned in RFC 3679
// Options 224-254 are reserved for private use
OptionEnd optionCode = 255
)
var optionCodeToString = map[OptionCode]string{
OptionPad: "Pad",
OptionSubnetMask: "Subnet Mask",
OptionTimeOffset: "Time Offset",
OptionRouter: "Router",
OptionTimeServer: "Time Server",
OptionNameServer: "Name Server",
OptionDomainNameServer: "Domain Name Server",
OptionLogServer: "Log Server",
OptionQuoteServer: "Quote Server",
OptionLPRServer: "LPR Server",
OptionImpressServer: "Impress Server",
OptionResourceLocationServer: "Resource Location Server",
OptionHostName: "Host Name",
OptionBootFileSize: "Boot File Size",
OptionMeritDumpFile: "Merit Dump File",
OptionDomainName: "Domain Name",
OptionSwapServer: "Swap Server",
OptionRootPath: "Root Path",
OptionExtensionsPath: "Extensions Path",
OptionIPForwarding: "IP Forwarding enable/disable",
OptionNonLocalSourceRouting: "Non-local Source Routing enable/disable",
OptionPolicyFilter: "Policy Filter",
OptionMaximumDatagramAssemblySize: "Maximum Datagram Reassembly Size",
OptionDefaultIPTTL: "Default IP Time-to-live",
OptionPathMTUAgingTimeout: "Path MTU Aging Timeout",
OptionPathMTUPlateauTable: "Path MTU Plateau Table",
OptionInterfaceMTU: "Interface MTU",
OptionAllSubnetsAreLocal: "All Subnets Are Local",
OptionBroadcastAddress: "Broadcast Address",
OptionPerformMaskDiscovery: "Perform Mask Discovery",
OptionMaskSupplier: "Mask Supplier",
OptionPerformRouterDiscovery: "Perform Router Discovery",
OptionRouterSolicitationAddress: "Router Solicitation Address",
OptionStaticRoutingTable: "Static Routing Table",
OptionTrailerEncapsulation: "Trailer Encapsulation",
OptionArpCacheTimeout: "ARP Cache Timeout",
OptionEthernetEncapsulation: "Ethernet Encapsulation",
OptionDefaulTCPTTL: "Default TCP TTL",
OptionTCPKeepaliveInterval: "TCP Keepalive Interval",
OptionTCPKeepaliveGarbage: "TCP Keepalive Garbage",
OptionNetworkInformationServiceDomain: "Network Information Service Domain",
OptionNetworkInformationServers: "Network Information Servers",
OptionNTPServers: "NTP Servers",
OptionVendorSpecificInformation: "Vendor Specific Information",
OptionNetBIOSOverTCPIPNameServer: "NetBIOS over TCP/IP Name Server",
OptionNetBIOSOverTCPIPDatagramDistributionServer: "NetBIOS over TCP/IP Datagram Distribution Server",
OptionNetBIOSOverTCPIPNodeType: "NetBIOS over TCP/IP Node Type",
OptionNetBIOSOverTCPIPScope: "NetBIOS over TCP/IP Scope",
OptionXWindowSystemFontServer: "X Window System Font Server",
OptionXWindowSystemDisplayManger: "X Window System Display Manager",
OptionRequestedIPAddress: "Requested IP Address",
OptionIPAddressLeaseTime: "IP Addresses Lease Time",
OptionOptionOverload: "Option Overload",
OptionDHCPMessageType: "DHCP Message Type",
OptionServerIdentifier: "Server Identifier",
OptionParameterRequestList: "Parameter Request List",
OptionMessage: "Message",
OptionMaximumDHCPMessageSize: "Maximum DHCP Message Size",
OptionRenewTimeValue: "Renew Time Value",
OptionRebindingTimeValue: "Rebinding Time Value",
OptionClassIdentifier: "Class Identifier",
OptionClientIdentifier: "Client identifier",
OptionNetWareIPDomainName: "NetWare/IP Domain Name",
OptionNetWareIPInformation: "NetWare/IP Information",
OptionNetworkInformationServicePlusDomain: "Network Information Service+ Domain",
OptionNetworkInformationServicePlusServers: "Network Information Service+ Servers",
OptionTFTPServerName: "TFTP Server Name",
OptionBootfileName: "Bootfile Name",
OptionMobileIPHomeAgent: "Mobile IP Home Agent",
OptionSimpleMailTransportProtocolServer: "SMTP Server",
OptionPostOfficeProtocolServer: "POP Server",
OptionNetworkNewsTransportProtocolServer: "NNTP Server",
OptionDefaultWorldWideWebServer: "Default WWW Server",
OptionDefaultFingerServer: "Default Finger Server",
OptionDefaultInternetRelayChatServer: "Default IRC Server",
OptionStreetTalkServer: "StreetTalk Server",
OptionStreetTalkDirectoryAssistanceServer: "StreetTalk Directory Assistance Server",
OptionUserClassInformation: "User Class Information",
OptionSLPDirectoryAgent: "SLP DIrectory Agent",
OptionSLPServiceScope: "SLP Service Scope",
OptionRapidCommit: "Rapid Commit",
OptionFQDN: "FQDN",
OptionRelayAgentInformation: "Relay Agent Information",
OptionInternetStorageNameService: "Internet Storage Name Service",
// Option 84 returned in RFC 3679
OptionNDSServers: "NDS Servers",
OptionNDSTreeName: "NDS Tree Name",
OptionNDSContext: "NDS Context",
OptionBCMCSControllerDomainNameList: "BCMCS Controller Domain Name List",
OptionBCMCSControllerIPv4AddressList: "BCMCS Controller IPv4 Address List",
OptionAuthentication: "Authentication",
OptionClientLastTransactionTime: "Client Last Transaction Time",
OptionAssociatedIP: "Associated IP",
OptionClientSystemArchitectureType: "Client System Architecture Type",
OptionClientNetworkInterfaceIdentifier: "Client Network Interface Identifier",
OptionLDAP: "LDAP",
// Option 96 returned in RFC 3679
OptionClientMachineIdentifier: "Client Machine Identifier",
OptionOpenGroupUserAuthentication: "OpenGroup's User Authentication",
OptionGeoConfCivic: "GEOCONF_CIVIC",
OptionIEEE10031TZString: "IEEE 1003.1 TZ String",
OptionReferenceToTZDatabase: "Reference to the TZ Database",
// Options 102-111 returned in RFC 3679
OptionNetInfoParentServerAddress: "NetInfo Parent Server Address",
OptionNetInfoParentServerTag: "NetInfo Parent Server Tag",
OptionURL: "URL",
// Option 115 returned in RFC 3679
OptionAutoConfigure: "Auto-Configure",
OptionNameServiceSearch: "Name Service Search",
OptionSubnetSelection: "Subnet Selection",
OptionDNSDomainSearchList: "DNS Domain Search List",
OptionSIPServers: "SIP Servers",
OptionClasslessStaticRoute: "Classless Static Route",
OptionCCC: "CCC, CableLabs Client Configuration",
OptionGeoConf: "GeoConf",
OptionVendorIdentifyingVendorClass: "Vendor-Identifying Vendor Class",
OptionVendorIdentifyingVendorSpecific: "Vendor-Identifying Vendor-Specific",
// Options 126-127 returned in RFC 3679
OptionTFTPServerIPAddress: "TFTP Server IP Address",
OptionCallServerIPAddress: "Call Server IP Address",
OptionDiscriminationString: "Discrimination String",
OptionRemoteStatisticsServerIPAddress: "RemoteStatistics Server IP Address",
Option8021PVLANID: "802.1P VLAN ID",
Option8021QL2Priority: "802.1Q L2 Priority",
OptionDiffservCodePoint: "Diffserv Code Point",
OptionHTTPProxyForPhoneSpecificApplications: "HTTP Proxy for phone-specific applications",
OptionPANAAuthenticationAgent: "PANA Authentication Agent",
OptionLoSTServer: "LoST Server",
OptionCAPWAPAccessControllerAddresses: "CAPWAP Access Controller Addresses",
OptionOPTIONIPv4AddressMoS: "OPTION-IPv4_Address-MoS",
OptionOPTIONIPv4FQDNMoS: "OPTION-IPv4_FQDN-MoS",
OptionSIPUAConfigurationServiceDomains: "SIP UA Configuration Service Domains",
OptionOPTIONIPv4AddressANDSF: "OPTION-IPv4_Address-ANDSF",
OptionOPTIONIPv6AddressANDSF: "OPTION-IPv6_Address-ANDSF",
// Options 144-149 returned in RFC 3679
OptionTFTPServerAddress: "TFTP Server Address",
OptionStatusCode: "Status Code",
OptionBaseTime: "Base Time",
OptionStartTimeOfState: "Start Time of State",
OptionQueryStartTime: "Query Start Time",
OptionQueryEndTime: "Query End Time",
OptionDHCPState: "DHCP Staet",
OptionDataSource: "Data Source",
// Options 158-174 returned in RFC 3679
OptionEtherboot: "Etherboot",
OptionIPTelephone: "IP Telephone",
OptionEtherbootPacketCableAndCableHome: "Etherboot / PacketCable and CableHome",
// Options 178-207 returned in RFC 3679
OptionPXELinuxMagicString: "PXELinux Magic String",
OptionPXELinuxConfigFile: "PXELinux Config File",
OptionPXELinuxPathPrefix: "PXELinux Path Prefix",
OptionPXELinuxRebootTime: "PXELinux Reboot Time",
OptionOPTION6RD: "OPTION_6RD",
OptionOPTIONv4AccessDomain: "OPTION_V4_ACCESS_DOMAIN",
// Options 214-219 returned in RFC 3679
OptionSubnetAllocation: "Subnet Allocation",
OptionVirtualSubnetAllocation: "Virtual Subnet Selection",
// Options 222-223 returned in RFC 3679
// Options 224-254 are reserved for private use
OptionEnd: "End",
}