github.com/jlowellwofford/u-root@v1.0.0/pkg/dhcp6client/packet.go (about)

     1  // Copyright 2017-2018 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package dhcp6client
     6  
     7  import (
     8  	"fmt"
     9  	"math/rand"
    10  	"net"
    11  
    12  	"github.com/mdlayher/dhcp6"
    13  	"github.com/mdlayher/dhcp6/dhcp6opts"
    14  )
    15  
    16  // RequestIANAFrom returns a Request packet to request an IANA from the server
    17  // that sent the given `ad` Advertisement.
    18  //
    19  // RFC 3315 Section 18.1.1. determines how a Request packet should be created.
    20  func RequestIANAFrom(ad *dhcp6.Packet) (*dhcp6.Packet, error) {
    21  	if ad.MessageType != dhcp6.MessageTypeAdvertise {
    22  		return nil, fmt.Errorf("need advertise packet")
    23  	}
    24  
    25  	// Must include; RFC 3315 Section 18.1.1.
    26  	clientID, err := dhcp6opts.GetClientID(ad.Options)
    27  	if err != nil {
    28  		return nil, fmt.Errorf("couldn't find client ID in %v: %v", ad, err)
    29  	}
    30  
    31  	serverID, err := dhcp6opts.GetServerID(ad.Options)
    32  	if err != nil {
    33  		return nil, fmt.Errorf("couldn't find server ID in %v: %v", ad, err)
    34  	}
    35  
    36  	opts := make(dhcp6.Options)
    37  	if err := opts.Add(dhcp6.OptionClientID, clientID); err != nil {
    38  		return nil, err
    39  	}
    40  	if err := opts.Add(dhcp6.OptionServerID, serverID); err != nil {
    41  		return nil, err
    42  	}
    43  	if err := newRequestOptions(opts); err != nil {
    44  		return nil, err
    45  	}
    46  
    47  	return NewPacket(dhcp6.MessageTypeRequest, opts), nil
    48  }
    49  
    50  func newRequestOptions(options dhcp6.Options) error {
    51  	// TODO: This should be generated.
    52  	id := [4]byte{'r', 'o', 'o', 't'}
    53  	iana := dhcp6opts.NewIANA(id, 0, 0, nil)
    54  	// IANA = requesting a non-temporary address.
    55  	if err := options.Add(dhcp6.OptionIANA, iana); err != nil {
    56  		return err
    57  	}
    58  	if err := options.Add(dhcp6.OptionElapsedTime, dhcp6opts.ElapsedTime(0)); err != nil {
    59  		return err
    60  	}
    61  
    62  	oro := dhcp6opts.OptionRequestOption{
    63  		dhcp6.OptionDNSServers,
    64  		dhcp6.OptionBootFileURL,
    65  		dhcp6.OptionBootFileParam,
    66  	}
    67  	// Must include; RFC 3315 Section 18.1.1.
    68  	return options.Add(dhcp6.OptionORO, oro)
    69  }
    70  
    71  func newSolicitOptions(mac net.HardwareAddr) (dhcp6.Options, error) {
    72  	options := make(dhcp6.Options)
    73  
    74  	if err := newRequestOptions(options); err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	if err := options.Add(dhcp6.OptionClientID, dhcp6opts.NewDUIDLL(6, mac)); err != nil {
    79  		return nil, err
    80  	}
    81  	return options, nil
    82  }
    83  
    84  // NewRapidSolicit returns a Solicit packet with the RapidCommit option.
    85  func NewRapidSolicit(mac net.HardwareAddr) (*dhcp6.Packet, error) {
    86  	p, err := NewSolicitPacket(mac)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	// Request an immediate Reply with an IP instead of an Advertise packet.
    92  	if err := p.Options.Add(dhcp6.OptionRapidCommit, nil); err != nil {
    93  		return nil, err
    94  	}
    95  	return p, nil
    96  }
    97  
    98  // NewSolicitPacket returns a Solicit packet.
    99  //
   100  // TODO(hugelgupf): Conform to RFC 3315 Section 17.1.1.
   101  func NewSolicitPacket(mac net.HardwareAddr) (*dhcp6.Packet, error) {
   102  	options, err := newSolicitOptions(mac)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  
   107  	return NewPacket(dhcp6.MessageTypeSolicit, options), nil
   108  }
   109  
   110  // NewPacket creates a new DHCPv6 packet using the given message type and
   111  // options.
   112  //
   113  // A transaction ID will be generated.
   114  func NewPacket(typ dhcp6.MessageType, opts dhcp6.Options) *dhcp6.Packet {
   115  	p := &dhcp6.Packet{
   116  		MessageType: typ,
   117  		Options:     opts,
   118  	}
   119  
   120  	// TODO: This may actually be bad news. Investigate whether we need to
   121  	// use crypto/rand. An attacker could inject a bad response if this is
   122  	// predictable. RFC 3315 has some words on this.
   123  	rand.Read(p.TransactionID[:])
   124  	return p
   125  }