Skip to content

Commit

Permalink
Add initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
Arnoud Vermeer committed Feb 28, 2019
1 parent 98218cf commit 8112d88
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 0 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
# tftp-proxy
A TFTP server that proxies request to an HTTP backend if a file is not found.

# How to build
go build tftp.go

# How to run
./tftp -url=http://example.com -dir=/var/lib/tftpboot &
84 changes: 84 additions & 0 deletions tftp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package main

import (
"errors"
"flag"
"fmt"
"io"
"net/http"
"os"
"time"

"github.com/pin/tftp"
)

var url string
var dir string

// readHandler is called when client starts file download from server
func readHandler(filename string, rf io.ReaderFrom) error {

if _, err := os.Stat(filename); err == nil {
file, err := os.Open(filename)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return err
}

fi, err := file.Stat()
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return err
}

rf.(tftp.OutgoingTransfer).SetSize(fi.Size())
n, err := rf.ReadFrom(file)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return err
}

fmt.Printf("%s %d bytes sent\n", filename, n)
} else { // File not found locally. Proxying the request.
fileUrl := url + "/" + filename
resp, err := http.Get(fileUrl)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return err
}
defer resp.Body.Close()

if resp.StatusCode != 200 {
return errors.New(fmt.Sprintf("Received status code: %d", resp.StatusCode))
}

rf.(tftp.OutgoingTransfer).SetSize(resp.ContentLength)
n, err := rf.ReadFrom(resp.Body)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return err
}

fmt.Printf("%s %d bytes sent\n", filename, n)
}

return nil
}

func main() {
flag.StringVar(&dir, "dir", "/var/lib/tftpboot", "The directory to serve files from. For example /var/lib/tftpboot")
flag.StringVar(&url, "url", "http://example.com", "The URL to proxy requests to. For example http://example.com")
flag.Parse()

// Change dir to the default tftp directory
os.Chdir(dir)

// use nil in place of handler to disable read or write operations
s := tftp.NewServer(readHandler, nil)
s.SetTimeout(5 * time.Second) // optional
err := s.ListenAndServe(":69") // blocks until s.Shutdown() is called
if err != nil {
fmt.Fprintf(os.Stdout, "server: %v\n", err)
os.Exit(1)
}
}

0 comments on commit 8112d88

Please sign in to comment.