github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/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 iSCSI root paths. 11 package netboot 12 13 import ( 14 "context" 15 "net" 16 "net/url" 17 "path" 18 19 "github.com/mvdan/u-root-coreutils/pkg/boot" 20 "github.com/mvdan/u-root-coreutils/pkg/boot/netboot/ipxe" 21 "github.com/mvdan/u-root-coreutils/pkg/boot/netboot/pxe" 22 "github.com/mvdan/u-root-coreutils/pkg/boot/netboot/simple" 23 "github.com/mvdan/u-root-coreutils/pkg/curl" 24 "github.com/mvdan/u-root-coreutils/pkg/dhclient" 25 "github.com/mvdan/u-root-coreutils/pkg/ulog" 26 ) 27 28 // BootImages figure out a ranked order of images to boot from the given DHCP lease. 29 // 30 // Tries, in order: 31 // 32 // - to detect an iPXE script beginning with #!ipxe, 33 // 34 // - to detect a pxelinux.0, in which case we will ignore the pxelinux.0 and 35 // try to parse pxelinux.cfg/<files>. 36 func BootImages(ctx context.Context, l ulog.Logger, s curl.Schemes, lease dhclient.Lease) ([]boot.OSImage, error) { 37 uri, err := lease.Boot() 38 if err != nil { 39 return nil, err 40 } 41 l.Printf("Boot URI: %s", uri) 42 43 // IP only makes sense for v4 anyway, because the PXE probing of files 44 // uses a MAC address and an IPv4 address to look at files. 45 var ip net.IP 46 if p4, ok := lease.(*dhclient.Packet4); ok { 47 ip = p4.Lease().IP 48 } 49 return getBootImages(ctx, l, s, uri, lease.Link().Attrs().HardwareAddr, ip), nil 50 } 51 52 // getBootImages attempts to parse the file at uri as an ipxe config and returns 53 // the ipxe boot image. Otherwise falls back to pxe and uses the uri directory, 54 // ip, and mac address to search for pxe configs. 55 func getBootImages(ctx context.Context, l ulog.Logger, schemes curl.Schemes, uri *url.URL, mac net.HardwareAddr, ip net.IP) []boot.OSImage { 56 var images []boot.OSImage 57 58 // 1: Attempt to download the given url as is. 59 // 60 // 1.1: Try ipxe config file. 61 ipc, err := ipxe.ParseConfig(ctx, l, uri, schemes) 62 if err != nil { 63 l.Printf("Parsing boot files as iPXE failed, trying other formats...: %v", err) 64 } 65 if ipc != nil { 66 images = append(images, ipc) 67 } 68 69 // 1.2: Check if target is a simple file instead of config script 70 if ipc == nil { 71 l.Printf("Trying to parse file as a non config Image...") 72 sImages, err := simple.FetchAndProbe(ctx, uri, schemes) 73 if err != nil { 74 l.Printf("failed to parse boot file as simple file: %v", err) 75 } 76 if sImages != nil { 77 images = append(images, sImages...) 78 } 79 } 80 81 // 2: Fallback to pxe boot. 82 // 83 // Look for pxelinux.cfg from parent directory of given url path. 84 wd := &url.URL{ 85 Scheme: uri.Scheme, 86 Host: uri.Host, 87 Path: path.Dir(uri.Path), 88 } 89 pxeImages, err := pxe.ParseConfig(ctx, wd, mac, ip, schemes) 90 if err != nil { 91 l.Printf("Failed to try parsing pxelinux config: %v", err) 92 } 93 94 return append(images, pxeImages...) 95 }