Skip to content

Commit

Permalink
add tftp server to allow grub with long path
Browse files Browse the repository at this point in the history
  • Loading branch information
aarnaud committed Jan 23, 2024
1 parent 3069b91 commit 77b290c
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 3 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
ipxeblue
vendors
.podman-data
.podman-data
!tftp/.gitkeep
tftp/
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ Supported environment variables
- default: `ipxeblue`
- `GRUB_SUPPORT_ENABLED`
- default: `False`
- `TFTP_ENABLED`
- default: `False`
- `DEFAULT_BOOTENTRY_NAME`
- default: ``

Expand Down
110 changes: 110 additions & 0 deletions controllers/tftp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package controllers

import (
"errors"
"fmt"
"github.com/aarnaud/ipxeblue/utils"
"github.com/pin/tftp/v3"
"github.com/rs/zerolog/log"
"gorm.io/gorm"
"io"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
)

func GetTFTPReader(config *utils.Config, db *gorm.DB) func(filename string, rf io.ReaderFrom) error {
folder := "tftp"
return func(filename string, rf io.ReaderFrom) error {
filename = strings.TrimRight(filename, "�")
raddr := rf.(tftp.OutgoingTransfer).RemoteAddr()
log.Info().Msgf("RRQ from %s filename %s", raddr.String(), filename)

path := filepath.Join(folder, filename)

// if file doesn't exist and path start by /grub/ use grubTFTP2HTTP
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) && strings.HasPrefix(filename, "/grub/") {
return grubTFTP2HTTP(config, db, filename, rf)
}

file, err := os.Open(path)
if err != nil {
log.Error().Err(err)
return err
}
stat, err := file.Stat()
if err != nil {
log.Error().Err(err)
return err
}
rf.(tftp.OutgoingTransfer).SetSize(stat.Size())
_, err = rf.ReadFrom(file)
if err != nil {
log.Error().Err(err)
return err
}
return nil
}
}

func GetTFTPWriter(config *utils.Config) func(filename string, wt io.WriterTo) error {
return func(filename string, wt io.WriterTo) error {
return nil
}
}

func grubTFTP2HTTP(config *utils.Config, db *gorm.DB, filename string, rf io.ReaderFrom) error {
gruburl, _ := url.Parse(config.BaseURL.String())
if filename == "/grub/grub.cfg" {
gruburl = gruburl.JoinPath("/grub/")
resp, err := http.Get(gruburl.String())
if err != nil {
return err
}
defer resp.Body.Close()
b, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
reader := strings.NewReader(string(b))
_, err = rf.ReadFrom(reader)
if err != nil {
return err
}
return nil
}

paths := strings.Split(filename, "/")
if len(paths) < 11 {
return fmt.Errorf("invalid path")
}
gruburl = gruburl.JoinPath("/grub/")
query := gruburl.Query()
query.Add("mac", paths[2])
query.Add("ip", paths[3])
query.Add("uuid", paths[4])
query.Add("asset", strings.TrimSpace(strings.TrimLeft(paths[5], "-")))
query.Add("manufacturer", strings.TrimLeft(paths[6], "-"))
query.Add("serial", strings.TrimLeft(paths[7], "-"))
query.Add("product", strings.TrimLeft(paths[8], "-"))
query.Add("buildarch", strings.TrimLeft(paths[9], "-"))
query.Add("platform", strings.TrimLeft(paths[10], "-"))
gruburl.RawQuery = query.Encode()
resp, err := http.Get(gruburl.String())
if err != nil {
return err
}
defer resp.Body.Close()
b, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
reader := strings.NewReader(string(b))
_, err = rf.ReadFrom(reader)
if err != nil {
return err
}
return nil
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/google/uuid v1.1.2
github.com/jackc/pgtype v1.5.0
github.com/minio/minio-go/v7 v7.0.6
github.com/pin/tftp/v3 v3.0.0
github.com/pkg/errors v0.9.1 // indirect
github.com/rs/zerolog v1.16.0
github.com/spf13/viper v1.7.1
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,8 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pin/tftp/v3 v3.0.0 h1:o9cQpmWBSbgiaYXuN+qJAB12XBIv4dT7OuOONucn2l0=
github.com/pin/tftp/v3 v3.0.0/go.mod h1:xwQaN4viYL019tM4i8iecm++5cGxSqen6AJEOEyEI0w=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
Expand Down Expand Up @@ -453,6 +455,7 @@ golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
Expand Down
18 changes: 18 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import (
"github.com/gin-contrib/cors"
"github.com/gin-contrib/logger"
"github.com/gin-gonic/gin"
"github.com/pin/tftp/v3"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
"net/http"
"os"
"time"
)

Expand Down Expand Up @@ -84,9 +86,24 @@ func main() {

if appconf.GrubSupportEnabled {
// Grub request without auth
log.Info().Msg("enabling grub http endpoint")
router.GET("/grub/", controllers.GrubScript)
}

// grub don't support long http queries
// using TFTP to pass positional metadata in tftp path
if appconf.TFTPEnabled {
s := tftp.NewServer(controllers.GetTFTPReader(appconf, db), controllers.GetTFTPWriter(appconf))
s.SetTimeout(30 * time.Second)
go func() {
log.Info().Msg("starting tftp server")
err := s.ListenAndServe(":69")
if err != nil {
fmt.Fprintf(os.Stdout, "server: %v\n", err)
}
}()
}

// iPXE request with auth
ipxeroute := router.Group("/", midlewares.BasicAuthIpxeAccount(false))
ipxeroute.GET("/", controllers.IpxeScript)
Expand Down Expand Up @@ -127,5 +144,6 @@ func main() {
v1.POST("/bootentries/:uuid/files/:name", controllers.UploadBootentryFile)
v1.GET("/bootentries/:uuid/files/:name", controllers.DownloadBootentryFile)

log.Info().Msg("starting http server")
router.Run(fmt.Sprintf(":%d", appconf.Port))
}
4 changes: 2 additions & 2 deletions templates/grub_index.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ smbios --type 1 --get-uuid 8 --set smbios_uuid
smbios --type 2 --get-string 8 --set smbios_asset
insmod http

echo "(http,{{ .Host }})/grub/?mac=$net_default_mac&ip=$net_default_ip&uuid=$smbios_uuid&sn=$smbios_serial&m=$smbios_manufacturer&c=$grub_cpu&t=$grub_platform"
source "(http,{{ .Host }})/grub/?mac=$net_default_mac&ip=$net_default_ip&uuid=$smbios_uuid&sn=$smbios_serial&m=$smbios_manufacturer&c=$grub_cpu&t=$grub_platform"
echo "(tftp)/grub/$net_default_mac/$net_default_ip/$smbios_uuid/-$smbios_asset/-$smbios_manufacturer/-$smbios_serial/-$smbios_product/$grub_cpu/$grub_platform/grub.cfg"
source "(tftp)/grub/$net_default_mac/$net_default_ip/$smbios_uuid/-$smbios_asset/-$smbios_manufacturer/-$smbios_serial/-$smbios_product/$grub_cpu/$grub_platform/grub.cfg"
Empty file added tftp/.gitkeep
Empty file.
3 changes: 3 additions & 0 deletions utils/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type Config struct {
MinioConfig MinioConfig
BaseURL *url.URL
GrubSupportEnabled bool
TFTPEnabled bool
DefaultBootentryName string
}

Expand All @@ -35,6 +36,7 @@ func GetConfig() *Config {
BucketName: "ipxeblue",
},
GrubSupportEnabled: false,
TFTPEnabled: false,
}

if p := viper.GetInt("PORT"); p != 0 {
Expand Down Expand Up @@ -69,6 +71,7 @@ func GetConfig() *Config {
config.BaseURL = u

config.GrubSupportEnabled = viper.GetBool("GRUB_SUPPORT_ENABLED")
config.TFTPEnabled = viper.GetBool("TFTP_ENABLED")
config.DefaultBootentryName = viper.GetString("DEFAULT_BOOTENTRY_NAME")

return &config
Expand Down

0 comments on commit 77b290c

Please sign in to comment.