github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+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 "context" 18 "net" 19 "net/url" 20 "path" 21 22 "github.com/u-root/u-root/pkg/boot" 23 "github.com/u-root/u-root/pkg/boot/netboot/ipxe" 24 "github.com/u-root/u-root/pkg/boot/netboot/pxe" 25 "github.com/u-root/u-root/pkg/curl" 26 "github.com/u-root/u-root/pkg/dhclient" 27 "github.com/u-root/u-root/pkg/ulog" 28 ) 29 30 // BootImages figure out a ranked order of images 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.0 and 37 // try 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 BootImages(ctx context.Context, l ulog.Logger, s curl.Schemes, lease dhclient.Lease) ([]boot.OSImage, error) { 42 uri, err := lease.Boot() 43 if err != nil { 44 return nil, err 45 } 46 l.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 getBootImages(ctx, l, s, uri, lease.Link().Attrs().HardwareAddr, ip), nil 55 } 56 57 // getBootImages 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 getBootImages(ctx context.Context, l ulog.Logger, schemes curl.Schemes, uri *url.URL, mac net.HardwareAddr, ip net.IP) []boot.OSImage { 61 var images []boot.OSImage 62 63 // Attempt to read the given boot path as an ipxe config file. 64 ipc, err := ipxe.ParseConfig(ctx, l, uri, schemes) 65 if err != nil { 66 l.Printf("Parsing boot files as iPXE failed, trying other formats...: %v", err) 67 } 68 if ipc != nil { 69 images = append(images, ipc) 70 } 71 72 // Fallback to pxe boot. 73 wd := &url.URL{ 74 Scheme: uri.Scheme, 75 Host: uri.Host, 76 Path: path.Dir(uri.Path), 77 } 78 pxeImages, err := pxe.ParseConfig(ctx, wd, mac, ip, schemes) 79 if err != nil { 80 l.Printf("Failed to try parsing pxelinux config: %v", err) 81 } 82 return append(images, pxeImages...) 83 }