diff --git a/NOTICE.txt b/NOTICE.txt index de100e42108..ffbdcfefbdb 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1325,6 +1325,42 @@ License type (autodetected): Apache-2.0 Apache License 2.0 +-------------------------------------------------------------------- +Dependency: github.com/insomniacslk/dhcp +Revision: 633285ba52b2a67b98a3026eb87ee1a76ab60f3c +License type (autodetected): BSD-3-Clause +./vendor/github.com/insomniacslk/dhcp/LICENSE: +-------------------------------------------------------------------- +BSD 3-Clause License + +Copyright (c) 2018, Andrea Barberio +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + -------------------------------------------------------------------- Dependency: github.com/joeshaw/multierror Revision: 69b34d4ec901851247ae7e77d33909caf9df99ed diff --git a/vendor/github.com/insomniacslk/dhcp/LICENSE b/vendor/github.com/insomniacslk/dhcp/LICENSE new file mode 100644 index 00000000000..c43d60d83e5 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2018, Andrea Barberio +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/bindtodevice_darwin.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/bindtodevice_darwin.go new file mode 100644 index 00000000000..e9580ce7486 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/bindtodevice_darwin.go @@ -0,0 +1,16 @@ +// +build darwin + +package dhcpv4 + +import ( + "net" + "syscall" +) + +func BindToInterface(fd int, ifname string) error { + iface, err := net.InterfaceByName(ifname) + if err != nil { + return err + } + return syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_BOUND_IF, iface.Index) +} diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/bindtodevice_linux.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/bindtodevice_linux.go new file mode 100644 index 00000000000..957744ac253 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/bindtodevice_linux.go @@ -0,0 +1,11 @@ +// +build linux + +package dhcpv4 + +import ( + "syscall" +) + +func BindToInterface(fd int, ifname string) error { + return syscall.BindToDevice(fd, ifname) +} diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/client.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/client.go new file mode 100644 index 00000000000..1d5a60f5b15 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/client.go @@ -0,0 +1,227 @@ +// +build !windows + +package dhcpv4 + +import ( + "encoding/binary" + "errors" + "net" + "os" + "syscall" + "time" + + "golang.org/x/net/ipv4" +) + +// MaxUDPReceivedPacketSize is the (arbitrary) maximum UDP packet size supported +// by this library. Theoretically could be up to 65kb. +const ( + MaxUDPReceivedPacketSize = 8192 +) + +var ( + // DefaultReadTimeout is the time to wait after listening in which the + // exchange is considered failed. + DefaultReadTimeout = 3 * time.Second + + // DefaultWriteTimeout is the time to wait after sending in which the + // exchange is considered failed. + DefaultWriteTimeout = 3 * time.Second +) + +// Client is the object that actually performs the DHCP exchange. It currently +// only has read and write timeout values. +type Client struct { + ReadTimeout, WriteTimeout time.Duration +} + +// NewClient generates a new client to perform a DHCP exchange with, setting the +// read and write timeout fields to defaults. +func NewClient() *Client { + return &Client{ + ReadTimeout: DefaultReadTimeout, + WriteTimeout: DefaultWriteTimeout, + } +} + +// MakeRawBroadcastPacket converts payload (a serialized DHCPv4 packet) into a +// raw packet suitable for UDP broadcast. +func MakeRawBroadcastPacket(payload []byte) ([]byte, error) { + udp := make([]byte, 8) + binary.BigEndian.PutUint16(udp[:2], ClientPort) + binary.BigEndian.PutUint16(udp[2:4], ServerPort) + binary.BigEndian.PutUint16(udp[4:6], uint16(8+len(payload))) + binary.BigEndian.PutUint16(udp[6:8], 0) // try to offload the checksum + + h := ipv4.Header{ + Version: 4, + Len: 20, + TotalLen: 20 + len(udp) + len(payload), + TTL: 64, + Protocol: 17, // UDP + Dst: net.IPv4bcast, + Src: net.IPv4zero, + } + ret, err := h.Marshal() + if err != nil { + return nil, err + } + ret = append(ret, udp...) + ret = append(ret, payload...) + return ret, nil +} + +// MakeBroadcastSocket creates a socket that can be passed to syscall.Sendto +// that will send packets out to the broadcast address. +func MakeBroadcastSocket(ifname string) (int, error) { + fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW) + if err != nil { + return fd, err + } + err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) + if err != nil { + return fd, err + } + err = syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1) + if err != nil { + return fd, err + } + err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) + if err != nil { + return fd, err + } + err = BindToInterface(fd, ifname) + if err != nil { + return fd, err + } + return fd, nil +} + +// MakeListeningSocket creates a listening socket on 0.0.0.0 for the DHCP client +// port and returns it. +func MakeListeningSocket(ifname string) (int, error) { + fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) + if err != nil { + return fd, err + } + err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) + if err != nil { + return fd, err + } + var addr [4]byte + copy(addr[:], net.IPv4zero.To4()) + if err = syscall.Bind(fd, &syscall.SockaddrInet4{Port: ClientPort, Addr: addr}); err != nil { + return fd, err + } + err = BindToInterface(fd, ifname) + if err != nil { + return fd, err + } + return fd, nil +} + +// Exchange runs a full DORA transaction: Discover, Offer, Request, Acknowledge, +// over UDP. Does not retry in case of failures. Returns a list of DHCPv4 +// structures representing the exchange. It can contain up to four elements, +// ordered as Discovery, Offer, Request and Acknowledge. In case of errors, an +// error is returned, and the list of DHCPv4 objects will be shorted than 4, +// containing all the sent and received DHCPv4 messages. +func (c *Client) Exchange(ifname string, discover *DHCPv4) ([]DHCPv4, error) { + conversation := make([]DHCPv4, 1) + var err error + + // Get our file descriptor for the broadcast socket. + sfd, err := MakeBroadcastSocket(ifname) + if err != nil { + return conversation, err + } + rfd, err := MakeListeningSocket(ifname) + if err != nil { + return conversation, err + } + + // Discover + if discover == nil { + discover, err = NewDiscoveryForInterface(ifname) + if err != nil { + return conversation, err + } + } + conversation[0] = *discover + + // Offer + offer, err := BroadcastSendReceive(sfd, rfd, discover, c.ReadTimeout, c.WriteTimeout) + if err != nil { + return conversation, err + } + conversation = append(conversation, *offer) + + // Request + request, err := RequestFromOffer(*offer) + if err != nil { + return conversation, err + } + conversation = append(conversation, *request) + + // Ack + ack, err := BroadcastSendReceive(sfd, rfd, discover, c.ReadTimeout, c.WriteTimeout) + if err != nil { + return conversation, err + } + conversation = append(conversation, *ack) + return conversation, nil +} + +// BroadcastSendReceive broadcasts packet (with some write timeout) and waits for a +// response up to some read timeout value. +func BroadcastSendReceive(sendFd, recvFd int, packet *DHCPv4, readTimeout, writeTimeout time.Duration) (*DHCPv4, error) { + packetBytes, err := MakeRawBroadcastPacket(packet.ToBytes()) + if err != nil { + return nil, err + } + + // Create a goroutine to perform the blocking send, and time it out after + // a certain amount of time. + var destination [4]byte + copy(destination[:], net.IPv4bcast.To4()) + remoteAddr := syscall.SockaddrInet4{Port: ClientPort, Addr: destination} + recvErrors := make(chan error, 1) + var response *DHCPv4 + go func(errs chan<- error) { + conn, err := net.FileConn(os.NewFile(uintptr(recvFd), "")) + if err != nil { + errs <- err + return + } + defer conn.Close() + conn.SetReadDeadline(time.Now().Add(readTimeout)) + + buf := make([]byte, MaxUDPReceivedPacketSize) + n, _, _, _, err := conn.(*net.UDPConn).ReadMsgUDP(buf, []byte{}) + if err != nil { + errs <- err + return + } + + response, err = FromBytes(buf[:n]) + if err != nil { + errs <- err + return + } + recvErrors <- nil + }(recvErrors) + if err = syscall.Sendto(sendFd, packetBytes, 0, &remoteAddr); err != nil { + return nil, err + } + + select { + case err = <-recvErrors: + if err != nil { + return nil, err + } + case <-time.After(readTimeout): + return nil, errors.New("timed out while listening for replies") + } + + return response, nil +} diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/defaults.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/defaults.go new file mode 100644 index 00000000000..4faec2cc3c1 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/defaults.go @@ -0,0 +1,6 @@ +package dhcpv4 + +const ( + ServerPort = 67 + ClientPort = 68 +) diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/dhcpv4.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/dhcpv4.go new file mode 100644 index 00000000000..226c0774a82 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/dhcpv4.go @@ -0,0 +1,674 @@ +package dhcpv4 + +import ( + "crypto/rand" + "encoding/binary" + "errors" + "fmt" + "log" + "net" + "strings" + + "github.com/insomniacslk/dhcp/iana" +) + +// HeaderSize is the DHCPv4 header size in bytes. +const HeaderSize = 236 + +// MaxMessageSize is the maximum size in bytes that a DHCPv4 packet can hold. +const MaxMessageSize = 576 + +// DHCPv4 represents a DHCPv4 packet header and options. See the New* functions +// to build DHCPv4 packets. +type DHCPv4 struct { + opcode OpcodeType + hwType iana.HwTypeType + hwAddrLen uint8 + hopCount uint8 + transactionID uint32 + numSeconds uint16 + flags uint16 + clientIPAddr net.IP + yourIPAddr net.IP + serverIPAddr net.IP + gatewayIPAddr net.IP + clientHwAddr [16]byte + serverHostName [64]byte + bootFileName [128]byte + options []Option +} + +// IPv4AddrsForInterface obtains the currently-configured, non-loopback IPv4 +// addresses for iface. +func IPv4AddrsForInterface(iface *net.Interface) ([]net.IP, error) { + addrs, err := iface.Addrs() + var v4addrs []net.IP + if err != nil { + return v4addrs, err + } + 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() (*uint32, error) { + b := make([]byte, 4) + n, err := rand.Read(b) + if n != 4 { + return nil, errors.New("Invalid random sequence: smaller than 32 bits") + } + if err != nil { + return nil, err + } + tid := binary.LittleEndian.Uint32(b) + return &tid, nil +} + +// 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, NewOffer, NewRequest, NewAcknowledge, NewInform and +// NewRelease . +func New() (*DHCPv4, error) { + tid, err := GenerateTransactionID() + if err != nil { + return nil, err + } + d := DHCPv4{ + opcode: OpcodeBootRequest, + hwType: iana.HwTypeEthernet, + hwAddrLen: 6, + hopCount: 0, + transactionID: *tid, + numSeconds: 0, + flags: 0, + clientIPAddr: net.IPv4zero, + yourIPAddr: net.IPv4zero, + serverIPAddr: net.IPv4zero, + gatewayIPAddr: net.IPv4zero, + } + copy(d.clientHwAddr[:], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) + copy(d.serverHostName[:], []byte{}) + copy(d.bootFileName[:], []byte{}) + options, err := OptionsFromBytes(MagicCookie) + if err != nil { + return nil, err + } + d.options = options + 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) (*DHCPv4, error) { + d, err := New() + if err != nil { + return nil, err + } + // get hw addr + iface, err := net.InterfaceByName(ifname) + if err != nil { + return nil, err + } + d.SetOpcode(OpcodeBootRequest) + d.SetHwType(iana.HwTypeEthernet) + d.SetHwAddrLen(uint8(len(iface.HardwareAddr))) + d.SetClientHwAddr(iface.HardwareAddr) + d.SetBroadcast() + d.AddOption(&OptMessageType{MessageType: MessageTypeDiscover}) + d.AddOption(&OptParameterRequestList{ + RequestedOpts: []OptionCode{ + OptionSubnetMask, + OptionRouter, + OptionDomainName, + OptionDomainNameServer, + }, + }) + // the End option has to be added explicitly + d.AddOption(&OptionGeneric{OptionCode: OptionEnd}) + return d, nil +} + +// NewInformForInterface builds a new DHCPv4 Informational message with default +// Ethernet HW type and the hardware address obtained from the specified +// interface. It does NOT put a DHCP End option at the end. +func NewInformForInterface(ifname string, needsBroadcast bool) (*DHCPv4, error) { + d, err := New() + if err != nil { + return nil, err + } + + // get hw addr + iface, err := net.InterfaceByName(ifname) + if err != nil { + return nil, err + } + d.SetOpcode(OpcodeBootRequest) + d.SetHwType(iana.HwTypeEthernet) + d.SetHwAddrLen(uint8(len(iface.HardwareAddr))) + d.SetClientHwAddr(iface.HardwareAddr) + + if needsBroadcast { + d.SetBroadcast() + } else { + d.SetUnicast() + } + + // 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) + } + d.SetClientIPAddr(localIPs[0]) + + d.AddOption(&OptMessageType{MessageType: MessageTypeInform}) + return d, nil +} + +// RequestFromOffer builds a DHCPv4 request from an offer. +func RequestFromOffer(offer DHCPv4) (*DHCPv4, error) { + d, err := New() + if err != nil { + return nil, err + } + d.SetOpcode(OpcodeBootRequest) + d.SetHwType(offer.HwType()) + d.SetHwAddrLen(offer.HwAddrLen()) + hwaddr := offer.ClientHwAddr() + d.SetClientHwAddr(hwaddr[:]) + d.SetTransactionID(offer.TransactionID()) + if offer.IsBroadcast() { + d.SetBroadcast() + } else { + d.SetUnicast() + } + // find server IP address + var serverIP []byte + for _, opt := range offer.options { + if opt.Code() == OptionServerIdentifier { + serverIP = opt.(*OptServerIdentifier).ServerID + } + } + if serverIP == nil { + return nil, errors.New("Missing Server IP Address in DHCP Offer") + } + d.SetServerIPAddr(serverIP) + d.AddOption(&OptMessageType{MessageType: MessageTypeRequest}) + d.AddOption(&OptRequestedIPAddress{RequestedAddr: offer.YourIPAddr()}) + d.AddOption(&OptServerIdentifier{ServerID: serverIP}) + // the End option has to be added explicitly + d.AddOption(&OptionGeneric{OptionCode: OptionEnd}) + return d, nil +} + +// FromBytes encodes the DHCPv4 packet into a sequence of bytes, and returns an +// error if the packet is not valid. +func FromBytes(data []byte) (*DHCPv4, error) { + if len(data) < HeaderSize { + return nil, fmt.Errorf("Invalid DHCPv4 header: shorter than %v bytes", HeaderSize) + } + d := DHCPv4{ + opcode: OpcodeType(data[0]), + hwType: iana.HwTypeType(data[1]), + hwAddrLen: data[2], + hopCount: data[3], + transactionID: binary.BigEndian.Uint32(data[4:8]), + numSeconds: binary.BigEndian.Uint16(data[8:10]), + flags: binary.BigEndian.Uint16(data[10:12]), + clientIPAddr: net.IP(data[12:16]), + yourIPAddr: net.IP(data[16:20]), + serverIPAddr: net.IP(data[20:24]), + gatewayIPAddr: net.IP(data[24:28]), + } + copy(d.clientHwAddr[:], data[28:44]) + copy(d.serverHostName[:], data[44:108]) + copy(d.bootFileName[:], data[108:236]) + options, err := OptionsFromBytes(data[236:]) + if err != nil { + return nil, err + } + d.options = options + return &d, nil +} + +// Opcode returns the OpcodeType for the packet, +func (d *DHCPv4) Opcode() OpcodeType { + return d.opcode +} + +// OpcodeToString returns the mnemonic name for the packet's opcode. +func (d *DHCPv4) OpcodeToString() string { + opcode := OpcodeToString[d.opcode] + if opcode == "" { + opcode = "Invalid" + } + return opcode +} + +// SetOpcode sets a new opcode for the packet. It prints a warning if the opcode +// is unknown, but does not generate an error. +func (d *DHCPv4) SetOpcode(opcode OpcodeType) { + if OpcodeToString[opcode] == "" { + log.Printf("Warning: unknown DHCPv4 opcode: %v", opcode) + } + d.opcode = opcode +} + +// HwType returns the hardware type as defined by IANA. +func (d *DHCPv4) HwType() iana.HwTypeType { + return d.hwType +} + +// HwTypeToString returns the mnemonic name for the hardware type, e.g. +// "Ethernet". If the type is unknown, it returns "Unknown". +func (d *DHCPv4) HwTypeToString() string { + hwtype, ok := iana.HwTypeToString[d.hwType] + if !ok { + hwtype = "Invalid" + } + return hwtype +} + +// SetHwType returns the hardware type as defined by IANA. +func (d *DHCPv4) SetHwType(hwType iana.HwTypeType) { + if _, ok := iana.HwTypeToString[hwType]; !ok { + log.Printf("Warning: Invalid DHCPv4 hwtype: %v", hwType) + } + d.hwType = hwType +} + +// HwAddrLen returns the hardware address length. E.g. for Ethernet it would +// return 6. +func (d *DHCPv4) HwAddrLen() uint8 { + return d.hwAddrLen +} + +// SetHwAddrLen sets the hardware address length, limiting it to the maximum +// size 16 that the standard allows. +func (d *DHCPv4) SetHwAddrLen(hwAddrLen uint8) { + if hwAddrLen > 16 { + log.Printf("Warning: invalid HwAddrLen: %v > 16, using 16 instead", hwAddrLen) + hwAddrLen = 16 + } + d.hwAddrLen = hwAddrLen +} + +// HopCount returns the hop count field. +func (d *DHCPv4) HopCount() uint8 { + return d.hopCount +} + +// SetHopCount sets the hop count value. +func (d *DHCPv4) SetHopCount(hopCount uint8) { + d.hopCount = hopCount +} + +// TransactionID returns the transaction ID as 32 bit unsigned integer. +func (d *DHCPv4) TransactionID() uint32 { + return d.transactionID +} + +// SetTransactionID sets the value for the transaction ID. +func (d *DHCPv4) SetTransactionID(transactionID uint32) { + d.transactionID = transactionID +} + +// NumSeconds returns the number of seconds. +func (d *DHCPv4) NumSeconds() uint16 { + return d.numSeconds +} + +// SetNumSeconds sets the seconds field. +func (d *DHCPv4) SetNumSeconds(numSeconds uint16) { + d.numSeconds = numSeconds +} + +// Flags returns the DHCP flags portion of the packet. +func (d *DHCPv4) Flags() uint16 { + return d.flags +} + +// SetFlags sets the flags field in the packet. +func (d *DHCPv4) SetFlags(flags uint16) { + d.flags = flags +} + +// 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) +} + +// ClientIPAddr returns the client IP address. +func (d *DHCPv4) ClientIPAddr() net.IP { + return d.clientIPAddr +} + +// SetClientIPAddr sets the client IP address. +func (d *DHCPv4) SetClientIPAddr(clientIPAddr net.IP) { + d.clientIPAddr = clientIPAddr +} + +// YourIPAddr returns the "your IP address" field. +func (d *DHCPv4) YourIPAddr() net.IP { + return d.yourIPAddr +} + +// SetYourIPAddr sets the "your IP address" field. +func (d *DHCPv4) SetYourIPAddr(yourIPAddr net.IP) { + d.yourIPAddr = yourIPAddr +} + +// ServerIPAddr returns the server IP address. +func (d *DHCPv4) ServerIPAddr() net.IP { + return d.serverIPAddr +} + +// SetServerIPAddr sets the server IP address. +func (d *DHCPv4) SetServerIPAddr(serverIPAddr net.IP) { + d.serverIPAddr = serverIPAddr +} + +// GatewayIPAddr returns the gateway IP address. +func (d *DHCPv4) GatewayIPAddr() net.IP { + return d.gatewayIPAddr +} + +// SetGatewayIPAddr sets the gateway IP address. +func (d *DHCPv4) SetGatewayIPAddr(gatewayIPAddr net.IP) { + d.gatewayIPAddr = gatewayIPAddr +} + +// ClientHwAddr returns the client hardware (MAC) address. +func (d *DHCPv4) ClientHwAddr() [16]byte { + return d.clientHwAddr +} + +// ClientHwAddrToString converts the hardware address field to a string. +func (d *DHCPv4) ClientHwAddrToString() string { + var ret []string + for _, b := range d.clientHwAddr[:d.hwAddrLen] { + ret = append(ret, fmt.Sprintf("%02x", b)) + } + return strings.Join(ret, ":") +} + +// SetClientHwAddr sets the client hardware address. +func (d *DHCPv4) SetClientHwAddr(clientHwAddr []byte) { + if len(clientHwAddr) > 16 { + log.Printf("Warning: too long HW Address (%d bytes), truncating to 16 bytes", len(clientHwAddr)) + clientHwAddr = clientHwAddr[:16] + } + copy(d.clientHwAddr[:len(clientHwAddr)], clientHwAddr) + // pad the remaining bytes, if any + for i := len(clientHwAddr); i < 16; i++ { + d.clientHwAddr[i] = 0 + } +} + +// ServerHostName returns the server host name as a sequence of bytes. +func (d *DHCPv4) ServerHostName() [64]byte { + return d.serverHostName +} + +// ServerHostNameToString returns the server host name as a string, after +// trimming the null bytes at the end. +func (d *DHCPv4) ServerHostNameToString() string { + return strings.TrimRight(string(d.serverHostName[:]), "\x00") +} + +// SetServerHostName replaces the server host name, from a sequence of bytes, +// truncating it to the maximum length of 64. +func (d *DHCPv4) SetServerHostName(serverHostName []byte) { + if len(serverHostName) > 64 { + serverHostName = serverHostName[:64] + } else if len(serverHostName) < 64 { + for i := len(serverHostName) - 1; i < 64; i++ { + serverHostName = append(serverHostName, 0) + } + } + // need an array, not a slice, so let's copy it + var newServerHostName [64]byte + copy(newServerHostName[:], serverHostName) + d.serverHostName = newServerHostName +} + +// BootFileName returns the boot file name as a sequence of bytes. +func (d *DHCPv4) BootFileName() [128]byte { + return d.bootFileName +} + +// BootFileNameToString returns the boot file name as a string, after trimming +// the null bytes at the end. +func (d *DHCPv4) BootFileNameToString() string { + return strings.TrimRight(string(d.bootFileName[:]), "\x00") +} + +// SetBootFileName replaces the boot file name, from a sequence of bytes, +// truncating it to the maximum length oh 128. +func (d *DHCPv4) SetBootFileName(bootFileName []byte) { + if len(bootFileName) > 128 { + bootFileName = bootFileName[:128] + } else if len(bootFileName) < 128 { + for i := len(bootFileName) - 1; i < 128; i++ { + bootFileName = append(bootFileName, 0) + } + } + // need an array, not a slice, so let's copy it + var newBootFileName [128]byte + copy(newBootFileName[:], bootFileName) + d.bootFileName = newBootFileName +} + +// Options returns the DHCPv4 options defined for the packet. +func (d *DHCPv4) Options() []Option { + return d.options +} + +// GetOption 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. +func (d *DHCPv4) GetOption(code OptionCode) []Option { + opts := []Option{} + for _, opt := range d.Options() { + if opt.Code() == code { + opts = append(opts, opt) + } + } + return opts +} + +// GetOneOption will attempt to get an option that match a Option code. +// If there are multiple options with the same OptionCode it will only return +// the first one found. If no matching option is found nil will be returned. +func (d *DHCPv4) GetOneOption(code OptionCode) Option { + for _, opt := range d.Options() { + if opt.Code() == code { + return opt + } + } + return nil +} + +// StrippedOptions works like Options, but it does not return anything after the +// End option. +func (d *DHCPv4) StrippedOptions() []Option { + // differently from Options() this function strips away anything coming + // after the End option (normally just Pad options). + strippedOptions := []Option{} + for _, opt := range d.options { + strippedOptions = append(strippedOptions, opt) + if opt.Code() == OptionEnd { + break + } + } + return strippedOptions +} + +// SetOptions replaces the current options with the provided ones. +func (d *DHCPv4) SetOptions(options []Option) { + d.options = options +} + +// AddOption appends an option to the existing ones. +func (d *DHCPv4) AddOption(option Option) { + d.options = append(d.options, option) +} + +func (d *DHCPv4) String() string { + return fmt.Sprintf("DHCPv4(opcode=%v hwtype=%v hwaddr=%v)", + d.OpcodeToString(), d.HwTypeToString(), d.ClientHwAddr()) +} + +// Summary prints detailed information about the packet. +func (d *DHCPv4) Summary() string { + ret := fmt.Sprintf( + "DHCPv4\n"+ + " opcode=%v\n"+ + " hwtype=%v\n"+ + " hwaddrlen=%v\n"+ + " hopcount=%v\n"+ + " transactionid=0x%08x\n"+ + " numseconds=%v\n"+ + " flags=%v (0x%02x)\n"+ + " clientipaddr=%v\n"+ + " youripaddr=%v\n"+ + " serveripaddr=%v\n"+ + " gatewayipaddr=%v\n"+ + " clienthwaddr=%v\n"+ + " serverhostname=%v\n"+ + " bootfilename=%v\n", + d.OpcodeToString(), + d.HwTypeToString(), + d.HwAddrLen(), + d.HopCount(), + d.TransactionID(), + d.NumSeconds(), + d.FlagsToString(), + d.Flags(), + d.ClientIPAddr(), + d.YourIPAddr(), + d.ServerIPAddr(), + d.GatewayIPAddr(), + d.ClientHwAddrToString(), + d.ServerHostNameToString(), + d.BootFileNameToString(), + ) + ret += " options=\n" + for _, opt := range d.options { + optString := opt.String() + // 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) + if opt.Code() == OptionEnd { + break + } + } + return ret +} + +// ValidateOptions runs sanity checks on the DHCPv4 packet and prints a number +// of warnings if something is incorrect. +func (d *DHCPv4) ValidateOptions() { + // TODO find duplicate options + foundOptionEnd := false + for _, opt := range d.options { + if foundOptionEnd { + if opt.Code() == OptionEnd { + log.Print("Warning: found duplicate End option") + } + if opt.Code() != OptionEnd && opt.Code() != OptionPad { + name := OptionCodeToString[opt.Code()] + log.Printf("Warning: found option %v (%v) after End option", opt.Code(), name) + } + } + if opt.Code() == OptionEnd { + foundOptionEnd = true + } + } + if !foundOptionEnd { + log.Print("Warning: no End option found") + } +} + +// ToBytes encodes a DHCPv4 structure into a sequence of bytes in its wire +// format. +func (d *DHCPv4) ToBytes() []byte { + // This won't check if the End option is present, you've been warned + var ret []byte + u32 := make([]byte, 4) + u16 := make([]byte, 2) + + ret = append(ret, byte(d.opcode)) + ret = append(ret, byte(d.hwType)) + ret = append(ret, byte(d.hwAddrLen)) + ret = append(ret, byte(d.hopCount)) + binary.BigEndian.PutUint32(u32, d.transactionID) + ret = append(ret, u32...) + binary.BigEndian.PutUint16(u16, d.numSeconds) + ret = append(ret, u16...) + binary.BigEndian.PutUint16(u16, d.flags) + ret = append(ret, u16...) + ret = append(ret, d.clientIPAddr[:4]...) + ret = append(ret, d.yourIPAddr[:4]...) + ret = append(ret, d.serverIPAddr[:4]...) + ret = append(ret, d.gatewayIPAddr[:4]...) + ret = append(ret, d.clientHwAddr[:16]...) + ret = append(ret, d.serverHostName[:64]...) + ret = append(ret, d.bootFileName[:128]...) + + d.ValidateOptions() // print warnings about broken options, if any + ret = append(ret, MagicCookie...) + for _, opt := range d.options { + ret = append(ret, opt.ToBytes()...) + } + return ret +} diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_broadcast_address.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_broadcast_address.go new file mode 100644 index 00000000000..ffa57e33d82 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_broadcast_address.go @@ -0,0 +1,56 @@ +package dhcpv4 + +import ( + "fmt" + "net" +) + +// This option implements the server identifier option +// https://tools.ietf.org/html/rfc2132 + +// OptBroadcastAddress represents an option encapsulating the server identifier. +type OptBroadcastAddress struct { + BroadcastAddress net.IP +} + +// ParseOptBroadcastAddress returns a new OptBroadcastAddress from a byte +// stream, or error if any. +func ParseOptBroadcastAddress(data []byte) (*OptBroadcastAddress, error) { + if len(data) < 2 { + return nil, ErrShortByteStream + } + code := OptionCode(data[0]) + if code != OptionBroadcastAddress { + return nil, fmt.Errorf("expected code %v, got %v", OptionBroadcastAddress, code) + } + length := int(data[1]) + if length != 4 { + return nil, fmt.Errorf("unexepcted length: expected 4, got %v", length) + } + if len(data) < 6 { + return nil, ErrShortByteStream + } + return &OptBroadcastAddress{BroadcastAddress: net.IP(data[2 : 2+length])}, nil +} + +// Code returns the option code. +func (o *OptBroadcastAddress) Code() OptionCode { + return OptionBroadcastAddress +} + +// ToBytes returns a serialized stream of bytes for this option. +func (o *OptBroadcastAddress) ToBytes() []byte { + ret := []byte{byte(o.Code()), byte(o.Length())} + return append(ret, o.BroadcastAddress.To4()...) +} + +// String returns a human-readable string. +func (o *OptBroadcastAddress) String() string { + return fmt.Sprintf("Broadcast Address -> %v", o.BroadcastAddress.String()) +} + +// Length returns the length of the data portion (excluding option code an byte +// length). +func (o *OptBroadcastAddress) Length() int { + return len(o.BroadcastAddress.To4()) +} diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_class_identifier.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_class_identifier.go new file mode 100644 index 00000000000..ae5dba2e1d9 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_class_identifier.go @@ -0,0 +1,52 @@ +package dhcpv4 + +import ( + "fmt" +) + +// This option implements the Class Identifier option +// https://tools.ietf.org/html/rfc2132 + +// OptClassIdentifier represents the DHCP message type option. +type OptClassIdentifier struct { + Identifier string +} + +// ParseOptClassIdentifier constructs an OptClassIdentifier struct from a sequence of +// bytes and returns it, or an error. +func ParseOptClassIdentifier(data []byte) (*OptClassIdentifier, error) { + // Should at least have code and length + if len(data) < 2 { + return nil, ErrShortByteStream + } + code := OptionCode(data[0]) + if code != OptionClassIdentifier { + return nil, fmt.Errorf("expected option %v, got %v instead", OptionClassIdentifier, code) + } + length := int(data[1]) + if len(data) < 2+length { + return nil, ErrShortByteStream + } + return &OptClassIdentifier{Identifier: string(data[2 : 2+length])}, nil +} + +// Code returns the option code. +func (o *OptClassIdentifier) Code() OptionCode { + return OptionClassIdentifier +} + +// ToBytes returns a serialized stream of bytes for this option. +func (o *OptClassIdentifier) ToBytes() []byte { + return append([]byte{byte(o.Code()), byte(o.Length())}, []byte(o.Identifier)...) +} + +// String returns a human-readable string for this option. +func (o *OptClassIdentifier) String() string { + return fmt.Sprintf("Class Identifier -> %v", o.Identifier) +} + +// Length returns the length of the data portion (excluding option code and byte +// for length, if any). +func (o *OptClassIdentifier) Length() int { + return len(o.Identifier) +} diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_domain_name.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_domain_name.go new file mode 100644 index 00000000000..71d7ef17b49 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_domain_name.go @@ -0,0 +1,49 @@ +package dhcpv4 + +import "fmt" + +// This option implements the server domani name option +// https://tools.ietf.org/html/rfc2132 + +// OptDomainName represents an option encapsulating the server identifier. +type OptDomainName struct { + DomainName string +} + +// ParseOptDomainName returns a new OptDomainName from a byte +// stream, or error if any. +func ParseOptDomainName(data []byte) (*OptDomainName, error) { + if len(data) < 2 { + return nil, ErrShortByteStream + } + code := OptionCode(data[0]) + if code != OptionDomainName { + return nil, fmt.Errorf("expected code %v, got %v", OptionDomainName, code) + } + length := int(data[1]) + if len(data) < 2+length { + return nil, ErrShortByteStream + } + return &OptDomainName{DomainName: string(data[2 : 2+length])}, nil +} + +// Code returns the option code. +func (o *OptDomainName) Code() OptionCode { + return OptionDomainName +} + +// ToBytes returns a serialized stream of bytes for this option. +func (o *OptDomainName) ToBytes() []byte { + return append([]byte{byte(o.Code()), byte(o.Length())}, []byte(o.DomainName)...) +} + +// String returns a human-readable string. +func (o *OptDomainName) String() string { + return fmt.Sprintf("Domain Name -> %v", o.DomainName) +} + +// Length returns the length of the data portion (excluding option code an byte +// length). +func (o *OptDomainName) Length() int { + return len(o.DomainName) +} diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_domain_name_server.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_domain_name_server.go new file mode 100644 index 00000000000..78aaf9001f3 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_domain_name_server.go @@ -0,0 +1,72 @@ +package dhcpv4 + +import ( + "fmt" + "net" +) + +// This option implements the domain name server option +// https://tools.ietf.org/html/rfc2132 + +// OptDomainNameServer represents an option encapsulating the domain name +// servers. +type OptDomainNameServer struct { + NameServers []net.IP +} + +// ParseOptDomainNameServer returns a new OptDomainNameServer from a byte +// stream, or error if any. +func ParseOptDomainNameServer(data []byte) (*OptDomainNameServer, error) { + if len(data) < 2 { + return nil, ErrShortByteStream + } + code := OptionCode(data[0]) + if code != OptionDomainNameServer { + return nil, fmt.Errorf("expected code %v, got %v", OptionDomainNameServer, code) + } + length := int(data[1]) + if length == 0 || length%4 != 0 { + return nil, fmt.Errorf("Invalid length: expected multiple of 4 larger than 4, got %v", length) + } + if len(data) < 2+length { + return nil, ErrShortByteStream + } + nameservers := make([]net.IP, 0, length%4) + for idx := 0; idx < length; idx += 4 { + b := data[2+idx : 2+idx+4] + nameservers = append(nameservers, net.IPv4(b[0], b[1], b[2], b[3])) + } + return &OptDomainNameServer{NameServers: nameservers}, nil +} + +// Code returns the option code. +func (o *OptDomainNameServer) Code() OptionCode { + return OptionDomainNameServer +} + +// ToBytes returns a serialized stream of bytes for this option. +func (o *OptDomainNameServer) ToBytes() []byte { + ret := []byte{byte(o.Code()), byte(o.Length())} + for _, ns := range o.NameServers { + ret = append(ret, ns...) + } + return ret +} + +// String returns a human-readable string. +func (o *OptDomainNameServer) String() string { + var servers string + for idx, ns := range o.NameServers { + servers += ns.String() + if idx < len(o.NameServers)-1 { + servers += ", " + } + } + return fmt.Sprintf("Domain Name Servers -> %v", servers) +} + +// Length returns the length of the data portion (excluding option code an byte +// length). +func (o *OptDomainNameServer) Length() int { + return len(o.NameServers) * 4 +} diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_generic.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_generic.go new file mode 100644 index 00000000000..0cecfd61dfa --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_generic.go @@ -0,0 +1,65 @@ +package dhcpv4 + +import ( + "errors" + "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 { + OptionCode OptionCode + Data []byte +} + +// ParseOptionGeneric parses a bytestream and creates a new OptionGeneric from +// it, or an error. +func ParseOptionGeneric(data []byte) (*OptionGeneric, error) { + if len(data) == 0 { + return nil, errors.New("invalid zero-length bytestream") + } + var ( + length int + optionData []byte + ) + code := OptionCode(data[0]) + if code != OptionPad && code != OptionEnd { + length = int(data[1]) + if len(data) < length+2 { + return nil, fmt.Errorf("invalid data length: declared %v, actual %v", length, len(data)) + } + optionData = data[2 : length+2] + } + return &OptionGeneric{OptionCode: code, Data: optionData}, nil +} + +// Code returns the generic option code. +func (o OptionGeneric) Code() OptionCode { + return o.OptionCode +} + +// ToBytes returns a serialized generic option as a slice of bytes. +func (o OptionGeneric) ToBytes() []byte { + ret := []byte{byte(o.OptionCode)} + if o.OptionCode == OptionEnd || o.OptionCode == OptionPad { + return ret + } + ret = append(ret, byte(o.Length())) + ret = append(ret, o.Data...) + return ret +} + +// String returns a human-readable representation of a generic option. +func (o OptionGeneric) String() string { + code, ok := OptionCodeToString[o.OptionCode] + if !ok { + code = "Unknown" + } + return fmt.Sprintf("%v -> %v", code, o.Data) +} + +// Length returns the number of bytes comprising the data section of the option. +func (o OptionGeneric) Length() int { + return len(o.Data) +} diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_maximum_dhcp_message_size.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_maximum_dhcp_message_size.go new file mode 100644 index 00000000000..05186f59ed5 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_maximum_dhcp_message_size.go @@ -0,0 +1,57 @@ +package dhcpv4 + +import ( + "encoding/binary" + "fmt" +) + +// This option implements the Maximum DHCP Message size option +// https://tools.ietf.org/html/rfc2132 + +// OptMaximumDHCPMessageSize represents the DHCP message type option. +type OptMaximumDHCPMessageSize struct { + Size uint16 +} + +// ParseOptMaximumDHCPMessageSize constructs an OptMaximumDHCPMessageSize struct from a sequence of +// bytes and returns it, or an error. +func ParseOptMaximumDHCPMessageSize(data []byte) (*OptMaximumDHCPMessageSize, error) { + // Should at least have code, length, and message type. + if len(data) < 4 { + return nil, ErrShortByteStream + } + code := OptionCode(data[0]) + if code != OptionMaximumDHCPMessageSize { + return nil, fmt.Errorf("expected option %v, got %v instead", OptionMaximumDHCPMessageSize, code) + } + length := int(data[1]) + if length != 2 { + return nil, fmt.Errorf("expected length 2, got %v instead", length) + } + msgSize := binary.BigEndian.Uint16(data[2:4]) + return &OptMaximumDHCPMessageSize{Size: msgSize}, nil +} + +// Code returns the option code. +func (o *OptMaximumDHCPMessageSize) Code() OptionCode { + return OptionMaximumDHCPMessageSize +} + +// ToBytes returns a serialized stream of bytes for this option. +func (o *OptMaximumDHCPMessageSize) ToBytes() []byte { + serializedSize := make([]byte, 2) + binary.BigEndian.PutUint16(serializedSize, o.Size) + serializedOpt := []byte{byte(o.Code()), byte(o.Length())} + return append(serializedOpt, serializedSize...) +} + +// String returns a human-readable string for this option. +func (o *OptMaximumDHCPMessageSize) String() string { + return fmt.Sprintf("Maximum DHCP Message Size -> %v", o.Size) +} + +// Length returns the length of the data portion (excluding option code and byte +// for length, if any). +func (o *OptMaximumDHCPMessageSize) Length() int { + return 2 +} diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_message_type.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_message_type.go new file mode 100644 index 00000000000..c47f137097e --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_message_type.go @@ -0,0 +1,57 @@ +package dhcpv4 + +import ( + "fmt" +) + +// This option implements the message type option +// https://tools.ietf.org/html/rfc2132 + +// OptMessageType represents the DHCP message type option. +type OptMessageType struct { + MessageType MessageType +} + +// ParseOptMessageType constructs an OptMessageType struct from a sequence of +// bytes and returns it, or an error. +func ParseOptMessageType(data []byte) (*OptMessageType, error) { + // Should at least have code, length, and message type. + if len(data) < 3 { + return nil, ErrShortByteStream + } + code := OptionCode(data[0]) + if code != OptionDHCPMessageType { + return nil, fmt.Errorf("expected option %v, got %v instead", OptionDHCPMessageType, code) + } + length := int(data[1]) + if length != 1 { + return nil, ErrShortByteStream + } + messageType := MessageType(data[2]) + return &OptMessageType{MessageType: messageType}, nil +} + +// Code returns the option code. +func (o *OptMessageType) Code() OptionCode { + return OptionDHCPMessageType +} + +// ToBytes returns a serialized stream of bytes for this option. +func (o *OptMessageType) ToBytes() []byte { + return []byte{byte(o.Code()), byte(o.Length()), byte(o.MessageType)} +} + +// String returns a human-readable string for this option. +func (o *OptMessageType) String() string { + s, ok := MessageTypeToString[o.MessageType] + if !ok { + s = "UNKNOWN" + } + return fmt.Sprintf("DHCP Message Type -> %s", s) +} + +// Length returns the length of the data portion (excluding option code and byte +// for length, if any). +func (o *OptMessageType) Length() int { + return 1 +} diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_parameter_request_list.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_parameter_request_list.go new file mode 100644 index 00000000000..324832edbb6 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_parameter_request_list.go @@ -0,0 +1,69 @@ +package dhcpv4 + +import ( + "fmt" + "strings" +) + +// This option implements the parameter request list option +// https://tools.ietf.org/html/rfc2132 + +// OptParameterRequestList represents the parameter request list option. +type OptParameterRequestList struct { + RequestedOpts []OptionCode +} + +// ParseOptParameterRequestList returns a new OptParameterRequestList from a +// byte stream, or error if any. +func ParseOptParameterRequestList(data []byte) (*OptParameterRequestList, error) { + // Should at least have code + length byte. + if len(data) < 2 { + return nil, ErrShortByteStream + } + code := OptionCode(data[0]) + if code != OptionParameterRequestList { + return nil, fmt.Errorf("expected code %v, got %v", OptionParameterRequestList, code) + } + length := int(data[1]) + if len(data) < length+2 { + return nil, ErrShortByteStream + } + var requestedOpts []OptionCode + for _, opt := range data[2 : length+2] { + requestedOpts = append(requestedOpts, OptionCode(opt)) + } + return &OptParameterRequestList{RequestedOpts: requestedOpts}, nil +} + +// Code returns the option code. +func (o *OptParameterRequestList) Code() OptionCode { + return OptionParameterRequestList +} + +// ToBytes returns a serialized stream of bytes for this option. +func (o *OptParameterRequestList) ToBytes() []byte { + ret := []byte{byte(o.Code()), byte(o.Length())} + for _, req := range o.RequestedOpts { + ret = append(ret, byte(req)) + } + return ret +} + +// String returns a human-readable string for this option. +func (o *OptParameterRequestList) String() string { + var optNames []string + for _, ro := range o.RequestedOpts { + if name, ok := OptionCodeToString[ro]; ok { + optNames = append(optNames, name) + } else { + optNames = append(optNames, fmt.Sprintf("Unknown (%v)", ro)) + } + } + return fmt.Sprintf("Parameter Request List -> [%v]", strings.Join(optNames, ", ")) +} + +// Length returns the length of the data portion (excluding option code and byte +// for length, if any). +func (o *OptParameterRequestList) Length() int { + return len(o.RequestedOpts) +} diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_requested_ip_address.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_requested_ip_address.go new file mode 100644 index 00000000000..8662263d061 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_requested_ip_address.go @@ -0,0 +1,57 @@ +package dhcpv4 + +import ( + "fmt" + "net" +) + +// This option implements the requested IP address option +// https://tools.ietf.org/html/rfc2132 + +// OptRequestedIPAddress represents an option encapsulating the server +// identifier. +type OptRequestedIPAddress struct { + RequestedAddr net.IP +} + +// ParseOptRequestedIPAddress returns a new OptServerIdentifier from a byte +// stream, or error if any. +func ParseOptRequestedIPAddress(data []byte) (*OptRequestedIPAddress, error) { + if len(data) < 2 { + return nil, ErrShortByteStream + } + code := OptionCode(data[0]) + if code != OptionRequestedIPAddress { + return nil, fmt.Errorf("expected code %v, got %v", OptionRequestedIPAddress, code) + } + length := int(data[1]) + if length != 4 { + return nil, fmt.Errorf("unexepcted length: expected 4, got %v", length) + } + if len(data) < 6 { + return nil, ErrShortByteStream + } + return &OptRequestedIPAddress{RequestedAddr: net.IP(data[2 : 2+length])}, nil +} + +// Code returns the option code. +func (o *OptRequestedIPAddress) Code() OptionCode { + return OptionRequestedIPAddress +} + +// ToBytes returns a serialized stream of bytes for this option. +func (o *OptRequestedIPAddress) ToBytes() []byte { + ret := []byte{byte(o.Code()), byte(o.Length())} + return append(ret, o.RequestedAddr.To4()...) +} + +// String returns a human-readable string. +func (o *OptRequestedIPAddress) String() string { + return fmt.Sprintf("Requested IP Address -> %v", o.RequestedAddr.String()) +} + +// Length returns the length of the data portion (excluding option code an byte +// length). +func (o *OptRequestedIPAddress) Length() int { + return len(o.RequestedAddr.To4()) +} diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_server_identifier.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_server_identifier.go new file mode 100644 index 00000000000..26c21a7f777 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_server_identifier.go @@ -0,0 +1,56 @@ +package dhcpv4 + +import ( + "fmt" + "net" +) + +// This option implements the server identifier option +// https://tools.ietf.org/html/rfc2132 + +// OptServerIdentifier represents an option encapsulating the server identifier. +type OptServerIdentifier struct { + ServerID net.IP +} + +// ParseOptServerIdentifier returns a new OptServerIdentifier from a byte +// stream, or error if any. +func ParseOptServerIdentifier(data []byte) (*OptServerIdentifier, error) { + if len(data) < 2 { + return nil, ErrShortByteStream + } + code := OptionCode(data[0]) + if code != OptionServerIdentifier { + return nil, fmt.Errorf("expected code %v, got %v", OptionServerIdentifier, code) + } + length := int(data[1]) + if length != 4 { + return nil, fmt.Errorf("unexepcted length: expected 4, got %v", length) + } + if len(data) < 6 { + return nil, ErrShortByteStream + } + return &OptServerIdentifier{ServerID: net.IP(data[2 : 2+length])}, nil +} + +// Code returns the option code. +func (o *OptServerIdentifier) Code() OptionCode { + return OptionServerIdentifier +} + +// ToBytes returns a serialized stream of bytes for this option. +func (o *OptServerIdentifier) ToBytes() []byte { + ret := []byte{byte(o.Code()), byte(o.Length())} + return append(ret, o.ServerID.To4()...) +} + +// String returns a human-readable string. +func (o *OptServerIdentifier) String() string { + return fmt.Sprintf("Server Identifier -> %v", o.ServerID.String()) +} + +// Length returns the length of the data portion (excluding option code an byte +// length). +func (o *OptServerIdentifier) Length() int { + return len(o.ServerID.To4()) +} diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_vivc.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_vivc.go new file mode 100644 index 00000000000..9be8557d0db --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/option_vivc.go @@ -0,0 +1,102 @@ +package dhcpv4 + +import ( + "bytes" + "encoding/binary" + "fmt" +) + +// This option implements the Vendor-Identifying Vendor Class Option +// https://tools.ietf.org/html/rfc3925 + +// VIVCIdentifier represents one Vendor-Identifying vendor class option. +type VIVCIdentifier struct { + EntID uint32 + Data []byte +} + +// OptVIVC represents the DHCP message type option. +type OptVIVC struct { + Identifiers []VIVCIdentifier +} + +// ParseOptVIVC contructs an OptVIVC tsruct from a sequence of bytes and returns +// it, or an error. +func ParseOptVIVC(data []byte) (*OptVIVC, error) { + if len(data) < 2 { + return nil, ErrShortByteStream + } + code := OptionCode(data[0]) + if code != OptionVendorIdentifyingVendorClass { + return nil, fmt.Errorf("expected code %v, got %v", OptionVendorIdentifyingVendorClass, code) + } + length := int(data[1]) + data = data[2:] + + if length != len(data) { + return nil, ErrShortByteStream + } + + ids := []VIVCIdentifier{} + for len(data) > 5 { + entID := binary.BigEndian.Uint32(data[0:4]) + idLen := int(data[4]) + data = data[5:] + + if idLen > len(data) { + return nil, ErrShortByteStream + } + + ids = append(ids, VIVCIdentifier{EntID: entID, Data: data[:idLen]}) + data = data[idLen:] + } + + if len(data) != 0 { + return nil, ErrShortByteStream + } + + return &OptVIVC{Identifiers: ids}, nil +} + +// Code returns the option code. +func (o *OptVIVC) Code() OptionCode { + return OptionVendorIdentifyingVendorClass +} + +// ToBytes returns a serialized stream of bytes for this option. +func (o *OptVIVC) ToBytes() []byte { + buf := make([]byte, o.Length()+2) + copy(buf[0:], []byte{byte(o.Code()), byte(o.Length())}) + + b := buf[2:] + for _, id := range o.Identifiers { + binary.BigEndian.PutUint32(b[0:4], id.EntID) + b[4] = byte(len(id.Data)) + copy(b[5:], id.Data) + b = b[len(id.Data)+5:] + } + return buf +} + +// String returns a human-readable string for this option. +func (o *OptVIVC) String() string { + buf := bytes.Buffer{} + fmt.Fprintf(&buf, "Vendor-Identifying Vendor Class ->") + + for _, id := range o.Identifiers { + fmt.Fprintf(&buf, " %d:'%s',", id.EntID, id.Data) + } + + return buf.String()[:buf.Len()-1] +} + +// Length returns the length of the data portion (excluding option code and byte +// for length, if any). +func (o *OptVIVC) Length() int { + n := 0 + for _, id := range o.Identifiers { + // each class has a header of endID (4 bytes) and length (1 byte) + n += 5 + len(id.Data) + } + return n +} diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/options.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/options.go new file mode 100644 index 00000000000..2bd26a59c4e --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/options.go @@ -0,0 +1,118 @@ +package dhcpv4 + +import ( + "bytes" + "errors" + "fmt" +) + +// ErrShortByteStream is an error that is thrown any time a short byte stream is +// detected during option parsing. +var ErrShortByteStream = errors.New("short byte stream") + +// ErrZeroLengthByteStream is an error that is thrown any time a zero-length +// byte stream is encountered. +var ErrZeroLengthByteStream = errors.New("zero-length byte stream") + +// MagicCookie is the magic 4-byte value at the beginning of the list of options +// in a DHCPv4 packet. +var MagicCookie = []byte{99, 130, 83, 99} + +// OptionCode is a single byte representing the code for a given Option. +type OptionCode byte + +// Option is an interface that all DHCP v4 options adhere to. +type Option interface { + Code() OptionCode + ToBytes() []byte + Length() int + String() string +} + +// ParseOption parses a sequence of bytes as a single DHCPv4 option, returning +// the specific option structure or error, if any. +func ParseOption(data []byte) (Option, error) { + if len(data) == 0 { + return nil, errors.New("invalid zero-length DHCPv4 option") + } + var ( + opt Option + err error + ) + switch OptionCode(data[0]) { + case OptionDHCPMessageType: + opt, err = ParseOptMessageType(data) + case OptionParameterRequestList: + opt, err = ParseOptParameterRequestList(data) + case OptionRequestedIPAddress: + opt, err = ParseOptRequestedIPAddress(data) + case OptionServerIdentifier: + opt, err = ParseOptServerIdentifier(data) + case OptionBroadcastAddress: + opt, err = ParseOptBroadcastAddress(data) + case OptionMaximumDHCPMessageSize: + opt, err = ParseOptMaximumDHCPMessageSize(data) + case OptionClassIdentifier: + opt, err = ParseOptClassIdentifier(data) + case OptionDomainName: + opt, err = ParseOptDomainName(data) + case OptionDomainNameServer: + opt, err = ParseOptDomainNameServer(data) + case OptionVendorIdentifyingVendorClass: + opt, err = ParseOptVIVC(data) + default: + opt, err = ParseOptionGeneric(data) + } + if err != nil { + return nil, err + } + return opt, nil +} + +// OptionsFromBytes parses a sequence of bytes until the end and builds a list +// of options from it. The sequence must contain the Magic Cookie. Returns an +// error if any invalid option or length is found. +func OptionsFromBytes(data []byte) ([]Option, error) { + if len(data) < len(MagicCookie) { + return nil, errors.New("invalid options: shorter than 4 bytes") + } + if !bytes.Equal(data[:len(MagicCookie)], MagicCookie) { + return nil, fmt.Errorf("invalid magic cookie: %v", data[:len(MagicCookie)]) + } + opts, err := OptionsFromBytesWithoutMagicCookie(data[len(MagicCookie):]) + if err != nil { + return nil, err + } + return opts, nil +} + +// OptionsFromBytesWithoutMagicCookie 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 OptionsFromBytesWithoutMagicCookie(data []byte) ([]Option, error) { + options := make([]Option, 0, 10) + idx := 0 + for { + if idx == len(data) { + break + } + // This should never happen. + if idx > len(data) { + return nil, errors.New("read past the end of options") + } + opt, err := ParseOption(data[idx:]) + idx++ + if err != nil { + return nil, err + } + options = append(options, opt) + + // Options with zero length have no length byte, so here we handle the + // ones with nonzero length + if opt.Length() > 0 { + idx++ + } + idx += opt.Length() + } + return options, nil +} diff --git a/vendor/github.com/insomniacslk/dhcp/dhcpv4/types.go b/vendor/github.com/insomniacslk/dhcp/dhcpv4/types.go new file mode 100644 index 00000000000..7c22bff30f3 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/dhcpv4/types.go @@ -0,0 +1,375 @@ +package dhcpv4 + +// values from http://www.networksorcery.com/enp/protocol/dhcp.htm and +// http://www.networksorcery.com/enp/protocol/bootp/options.htm + +// MessageType represents the possible DHCP message types - DISCOVER, OFFER, etc +type MessageType byte + +// DHCP message types +const ( + MessageTypeDiscover MessageType = 1 + MessageTypeOffer MessageType = 2 + MessageTypeRequest MessageType = 3 + MessageTypeDecline MessageType = 4 + MessageTypeAck MessageType = 5 + MessageTypeNak MessageType = 6 + MessageTypeRelease MessageType = 7 + MessageTypeInform MessageType = 8 +) + +// MessageTypeToString maps DHCP message types to human-readable strings. +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 +) + +// OpcodeToString maps an OpcodeType to its mnemonic name +var OpcodeToString = map[OpcodeType]string{ + OpcodeBootRequest: "BootRequest", + OpcodeBootReply: "BootReply", +} + +// 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 + OptionSIPServersDHCPOption OptionCode = 120 + OptionClasslessStaticRouteOption 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 +) + +// OptionCodeToString maps an OptionCode to its mnemonic name +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", + OptionSIPServersDHCPOption: "SIP Servers DHCP Option", + OptionClasslessStaticRouteOption: "Classless Static Route Option", + 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", +} diff --git a/vendor/github.com/insomniacslk/dhcp/iana/hwtypes.go b/vendor/github.com/insomniacslk/dhcp/iana/hwtypes.go new file mode 100644 index 00000000000..7467a78bdc1 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/iana/hwtypes.go @@ -0,0 +1,80 @@ +package iana + +type HwTypeType uint8 + +const ( + _ HwTypeType = iota // skip 0 + HwTypeEthernet + HwTypeExperimentalEthernet + HwTypeAmateurRadioAX25 + HwTypeProteonTokenRing + HwTypeChaos + HwTypeIEEE802 + HwTypeARCNET + HwTypeHyperchannel + HwTypeLanstar + HwTypeAutonet + HwTypeLocalTalk + HwTypeLocalNet + HwTypeUltraLink + HwTypeSMDS + HwTypeFrameRelay + HwTypeATM + HwTypeHDLC + HwTypeFibreChannel + HwTypeATM2 + HwTypeSerialLine + HwTypeATM3 + HwTypeMILSTD188220 + HwTypeMetricom + HwTypeIEEE1394 + HwTypeMAPOS + HwTypeTwinaxial + HwTypeEUI64 + HwTypeHIPARP + HwTypeISO7816 + HwTypeARPSec + HwTypeIPsec + HwTypeInfiniband + HwTypeCAI + HwTypeWiegandInterface + HwTypePureIP +) + +var HwTypeToString = map[HwTypeType]string{ + HwTypeEthernet: "Ethernet", + HwTypeExperimentalEthernet: "Experimental Ethernet", + HwTypeAmateurRadioAX25: "Amateur Radio AX.25", + HwTypeProteonTokenRing: "Proteon ProNET Token Ring", + HwTypeChaos: "Chaos", + HwTypeIEEE802: "IEEE 802", + HwTypeARCNET: "ARCNET", + HwTypeHyperchannel: "Hyperchannel", + HwTypeLanstar: "Lanstar", + HwTypeAutonet: "Autonet Short Address", + HwTypeLocalTalk: "LocalTalk", + HwTypeLocalNet: "LocalNet", + HwTypeUltraLink: "Ultra link", + HwTypeSMDS: "SMDS", + HwTypeFrameRelay: "Frame Relay", + HwTypeATM: "ATM", + HwTypeHDLC: "HDLC", + HwTypeFibreChannel: "Fibre Channel", + HwTypeATM2: "ATM 2", + HwTypeSerialLine: "Serial Line", + HwTypeATM3: "ATM 3", + HwTypeMILSTD188220: "MIL-STD-188-220", + HwTypeMetricom: "Metricom", + HwTypeIEEE1394: "IEEE 1394.1995", + HwTypeMAPOS: "MAPOS", + HwTypeTwinaxial: "Twinaxial", + HwTypeEUI64: "EUI-64", + HwTypeHIPARP: "HIPARP", + HwTypeISO7816: "IP and ARP over ISO 7816-3", + HwTypeARPSec: "ARPSec", + HwTypeIPsec: "IPsec tunnel", + HwTypeInfiniband: "Infiniband", + HwTypeCAI: "CAI, TIA-102 Project 125 Common Air Interface", + HwTypeWiegandInterface: "Wiegand Interface", + HwTypePureIP: "Pure IP", +} diff --git a/vendor/github.com/insomniacslk/dhcp/iana/statuscodes.go b/vendor/github.com/insomniacslk/dhcp/iana/statuscodes.go new file mode 100644 index 00000000000..47e81101c52 --- /dev/null +++ b/vendor/github.com/insomniacslk/dhcp/iana/statuscodes.go @@ -0,0 +1,32 @@ +package iana + +// StatusCode represents a IANA status code for DHCPv6 +type StatusCode uint16 + +// IANA status codes as defined by rfc 3315 par. 24..4 +const ( + StatusSuccess StatusCode = 0 + StatusUnspecFail StatusCode = 1 + StatusNoAddrsAvail StatusCode = 2 + StatusNoBinding StatusCode = 3 + StatusNotOnLink StatusCode = 4 + StatusUseMulticast StatusCode = 5 +) + +// StatusCodeToString returns a mnemonic name for a given status code +func StatusCodeToString(s StatusCode) string { + if sc := StatusCodeToStringMap[s]; sc != "" { + return sc + } + return "Unknown" +} + +// StatusCodeToStringMap maps status codes to their names +var StatusCodeToStringMap = map[StatusCode]string{ + StatusSuccess: "Success", + StatusUnspecFail: "UnspecFail", + StatusNoAddrsAvail: "NoAddrsAvail", + StatusNoBinding: "NoBinding", + StatusNotOnLink: "NotOnLink", + StatusUseMulticast: "UseMulticast", +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 1ae7be83144..daf3ef5cc70 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -1114,6 +1114,18 @@ "revision": "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75", "revisionTime": "2014-10-17T20:07:13Z" }, + { + "checksumSHA1": "5qaMTb8eLAwaTeCqSHYMVyb4BSM=", + "path": "github.com/insomniacslk/dhcp/dhcpv4", + "revision": "633285ba52b2a67b98a3026eb87ee1a76ab60f3c", + "revisionTime": "2018-07-16T14:52:14Z" + }, + { + "checksumSHA1": "AyBWbH2Ra2aFOO6tSk4aQaVqfBQ=", + "path": "github.com/insomniacslk/dhcp/iana", + "revision": "633285ba52b2a67b98a3026eb87ee1a76ab60f3c", + "revisionTime": "2018-07-16T14:52:14Z" + }, { "checksumSHA1": "l9wW52CYGbmO/NGwYZ/Op2QTmaA=", "path": "github.com/joeshaw/multierror",