github.com/system-transparency/u-root@v6.0.1-0.20190919065413-ed07a650de4c+incompatible/pkg/dhclient/dhcp6.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 dhclient
     6  
     7  import (
     8  	"fmt"
     9  	"net"
    10  	"net/url"
    11  
    12  	"github.com/insomniacslk/dhcp/dhcpv6"
    13  	"github.com/vishvananda/netlink"
    14  )
    15  
    16  // Packet6 implements Packet for IPv6 DHCP.
    17  type Packet6 struct {
    18  	p     *dhcpv6.Message
    19  	iface netlink.Link
    20  }
    21  
    22  // NewPacket6 wraps a DHCPv6 packet with some convenience methods.
    23  func NewPacket6(iface netlink.Link, p *dhcpv6.Message) *Packet6 {
    24  	return &Packet6{
    25  		p:     p,
    26  		iface: iface,
    27  	}
    28  }
    29  
    30  func (p *Packet6) Link() netlink.Link {
    31  	return p.iface
    32  }
    33  
    34  // Configure configures interface using this packet.
    35  func (p *Packet6) Configure() error {
    36  	return Configure6(p.iface, p.p)
    37  }
    38  
    39  func (p *Packet6) String() string {
    40  	return fmt.Sprintf("IPv6 DHCP Lease IP %s", p.Lease().IPv6Addr)
    41  }
    42  
    43  // Lease returns lease information assigned.
    44  func (p *Packet6) Lease() *dhcpv6.OptIAAddress {
    45  	// TODO(chrisko): Reform dhcpv6 option handling to be like dhcpv4.
    46  	ianaOpt := p.p.GetOneOption(dhcpv6.OptionIANA)
    47  	iana, ok := ianaOpt.(*dhcpv6.OptIANA)
    48  	if !ok {
    49  		return nil
    50  	}
    51  
    52  	iaAddrOpt := iana.Options.GetOne(dhcpv6.OptionIAAddr)
    53  	iaAddr, ok := iaAddrOpt.(*dhcpv6.OptIAAddress)
    54  	if !ok {
    55  		return nil
    56  	}
    57  	return iaAddr
    58  }
    59  
    60  // DNS returns DNS servers assigned.
    61  func (p *Packet6) DNS() []net.IP {
    62  	// TODO: Would the IANA contain this, or the packet?
    63  	dnsOpt := p.p.GetOneOption(dhcpv6.OptionDNSRecursiveNameServer)
    64  	dns, ok := dnsOpt.(*dhcpv6.OptDNSRecursiveNameServer)
    65  	if !ok {
    66  		return nil
    67  	}
    68  	return dns.NameServers
    69  }
    70  
    71  // Boot returns the boot file URL and parameters assigned.
    72  //
    73  // TODO: RFC 5970 is helpfully avoidant of where these options are used. Are
    74  // they added to the packet? Are they added to an IANA?  It *seems* like it's
    75  // in the packet.
    76  func (p *Packet6) Boot() (*url.URL, error) {
    77  	uriOpt := p.p.GetOneOption(dhcpv6.OptionBootfileURL)
    78  	uri, ok := uriOpt.(*dhcpv6.OptBootFileURL)
    79  	if !ok {
    80  		return nil, fmt.Errorf("packet does not contain boot file URL")
    81  	}
    82  	// Srsly, a []byte?
    83  	return url.Parse(string(uri.BootFileURL))
    84  }
    85  
    86  // ISCSIBoot returns the target address and volume name to boot from if
    87  // they were part of the DHCP message.
    88  //
    89  // Parses the DHCPv6 Boot File for iSCSI target and volume as specified by RFC
    90  // 4173 and RFC 5970.
    91  func (p *Packet6) ISCSIBoot() (*net.TCPAddr, string, error) {
    92  	uriOpt := p.p.GetOneOption(dhcpv6.OptionBootfileURL)
    93  	uri, ok := uriOpt.(*dhcpv6.OptBootFileURL)
    94  	if !ok {
    95  		return nil, "", fmt.Errorf("packet does not contain boot file URL")
    96  	}
    97  	return parseISCSIURI(string(uri.BootFileURL))
    98  }