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 }