github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/pkg/boot/netboot/netboot.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 netboot provides a one-stop shop for netboot parsing needs. 6 // 7 // netboot can take a URL from a DHCP lease and try to detect iPXE scripts and 8 // PXE scripts. 9 // 10 // TODO: detect multiboot and Linux kernels without configuration (URL points 11 // to a single kernel file). 12 // 13 // TODO: detect iSCSI root paths. 14 package netboot 15 16 import ( 17 "fmt" 18 "log" 19 "net" 20 "net/url" 21 "path" 22 23 "github.com/u-root/u-root/pkg/boot" 24 "github.com/u-root/u-root/pkg/boot/netboot/ipxe" 25 "github.com/u-root/u-root/pkg/boot/netboot/pxe" 26 "github.com/u-root/u-root/pkg/curl" 27 "github.com/u-root/u-root/pkg/dhclient" 28 ) 29 30 // BootImage figures out the image to boot from the given DHCP lease. 31 // 32 // Tries, in order: 33 // 34 // - to detect an iPXE script beginning with #!ipxe, 35 // 36 // - to detect a pxelinux.0, in which case we will ignore the pxelinux and try 37 // to parse pxelinux.cfg/<files>. 38 // 39 // TODO: detect straight up multiboot and bzImage Linux kernel files rather 40 // than just configuration scripts. 41 func BootImage(s curl.Schemes, lease dhclient.Lease) (*boot.LinuxImage, error) { 42 uri, err := lease.Boot() 43 if err != nil { 44 return nil, err 45 } 46 log.Printf("Boot URI: %s", uri) 47 48 // IP only makes sense for v4 anyway, because the PXE probing of files 49 // uses a MAC address and an IPv4 address to look at files. 50 var ip net.IP 51 if p4, ok := lease.(*dhclient.Packet4); ok { 52 ip = p4.Lease().IP 53 } 54 return getBootImage(s, uri, lease.Link().Attrs().HardwareAddr, ip) 55 } 56 57 // getBootImage attempts to parse the file at uri as an ipxe config and returns 58 // the ipxe boot image. Otherwise falls back to pxe and uses the uri directory, 59 // ip, and mac address to search for pxe configs. 60 func getBootImage(schemes curl.Schemes, uri *url.URL, mac net.HardwareAddr, ip net.IP) (*boot.LinuxImage, error) { 61 // Attempt to read the given boot path as an ipxe config file. 62 ipc, err := ipxe.ParseConfigWithSchemes(uri, schemes) 63 if err == nil { 64 return ipc, nil 65 } 66 log.Printf("Falling back to pxe boot: %v", err) 67 68 // Fallback to pxe boot. 69 wd := &url.URL{ 70 Scheme: uri.Scheme, 71 Host: uri.Host, 72 Path: path.Dir(uri.Path), 73 } 74 pc, err := pxe.ParseConfigWithSchemes(wd, mac, ip, schemes) 75 if err != nil { 76 return nil, fmt.Errorf("failed to parse pxelinux config: %v", err) 77 } 78 79 label, ok := pc.Entries[pc.DefaultEntry] 80 if !ok { 81 return nil, fmt.Errorf("Could not find %q from entries %v", pc.DefaultEntry, pc.Entries) 82 } 83 return label, nil 84 }