github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/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 "os" 12 13 "github.com/insomniacslk/dhcp/dhcpv6" 14 "github.com/vishvananda/netlink" 15 "golang.org/x/sys/unix" 16 ) 17 18 // Packet6 implements Packet for IPv6 DHCP. 19 type Packet6 struct { 20 p *dhcpv6.Message 21 iface netlink.Link 22 } 23 24 // NewPacket6 wraps a DHCPv6 packet with some convenience methods. 25 func NewPacket6(iface netlink.Link, p *dhcpv6.Message) *Packet6 { 26 return &Packet6{ 27 p: p, 28 iface: iface, 29 } 30 } 31 32 // Link returns the interface this packet was received for. 33 func (p *Packet6) Link() netlink.Link { 34 return p.iface 35 } 36 37 // Configure6 adds IPv6 addresses, routes, and DNS servers to the system. 38 func Configure6(iface netlink.Link, packet *dhcpv6.Message) error { 39 p := NewPacket6(iface, packet) 40 return p.Configure() 41 } 42 43 // Configure configures interface using this packet. 44 func (p *Packet6) Configure() error { 45 l := p.Lease() 46 if l == nil { 47 return fmt.Errorf("no lease returned") 48 } 49 50 // Add the address to the iface. 51 dst := &netlink.Addr{ 52 IPNet: &net.IPNet{ 53 IP: l.IPv6Addr, 54 Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff:ffff::")), 55 }, 56 PreferedLft: int(l.PreferredLifetime), 57 ValidLft: int(l.ValidLifetime), 58 // Optimistic DAD (Duplicate Address Detection) means we can 59 // use the address before DAD is complete. The DHCP server's 60 // job was to give us a unique IP so there is little risk of a 61 // collision. 62 Flags: unix.IFA_F_OPTIMISTIC, 63 } 64 if err := netlink.AddrReplace(p.iface, dst); err != nil { 65 if os.IsExist(err) { 66 return fmt.Errorf("add/replace %s to %v: %v", dst, p.iface, err) 67 } 68 } 69 70 if ips := p.DNS(); ips != nil { 71 if err := WriteDNSSettings(ips, nil, ""); err != nil { 72 return err 73 } 74 } 75 return nil 76 } 77 78 func (p *Packet6) String() string { 79 return fmt.Sprintf("IPv6 DHCP Lease IP %s", p.Lease().IPv6Addr) 80 } 81 82 // Lease returns lease information assigned. 83 func (p *Packet6) Lease() *dhcpv6.OptIAAddress { 84 // TODO(chrisko): Reform dhcpv6 option handling to be like dhcpv4. 85 ianaOpt := p.p.GetOneOption(dhcpv6.OptionIANA) 86 iana, ok := ianaOpt.(*dhcpv6.OptIANA) 87 if !ok { 88 return nil 89 } 90 91 iaAddrOpt := iana.Options.GetOne(dhcpv6.OptionIAAddr) 92 iaAddr, ok := iaAddrOpt.(*dhcpv6.OptIAAddress) 93 if !ok { 94 return nil 95 } 96 return iaAddr 97 } 98 99 // DNS returns DNS servers assigned. 100 func (p *Packet6) DNS() []net.IP { 101 // TODO: Would the IANA contain this, or the packet? 102 dnsOpt := p.p.GetOneOption(dhcpv6.OptionDNSRecursiveNameServer) 103 dns, ok := dnsOpt.(*dhcpv6.OptDNSRecursiveNameServer) 104 if !ok { 105 return nil 106 } 107 return dns.NameServers 108 } 109 110 // Boot returns the boot file URL and parameters assigned. 111 // 112 // TODO: RFC 5970 is helpfully avoidant of where these options are used. Are 113 // they added to the packet? Are they added to an IANA? It *seems* like it's 114 // in the packet. 115 func (p *Packet6) Boot() (*url.URL, error) { 116 uriOpt := p.p.GetOneOption(dhcpv6.OptionBootfileURL) 117 uri, ok := uriOpt.(*dhcpv6.OptBootFileURL) 118 if !ok { 119 return nil, fmt.Errorf("packet does not contain boot file URL") 120 } 121 // Srsly, a []byte? 122 return url.Parse(string(uri.ToBytes())) 123 } 124 125 // ISCSIBoot returns the target address and volume name to boot from if 126 // they were part of the DHCP message. 127 // 128 // Parses the DHCPv6 Boot File for iSCSI target and volume as specified by RFC 129 // 4173 and RFC 5970. 130 func (p *Packet6) ISCSIBoot() (*net.TCPAddr, string, error) { 131 uriOpt := p.p.GetOneOption(dhcpv6.OptionBootfileURL) 132 uri, ok := uriOpt.(*dhcpv6.OptBootFileURL) 133 if !ok { 134 return nil, "", fmt.Errorf("packet does not contain boot file URL") 135 } 136 return parseISCSIURI(string(uri.ToBytes())) 137 }