From e19a9ba4f580b46bcfe83264443522a9bc1fcc2a Mon Sep 17 00:00:00 2001 From: Pablu23 Date: Mon, 11 Dec 2023 12:04:20 +0100 Subject: [PATCH] Added Options and Path safety --- .gitignore | 1 + Makefile | 4 +- cmd/uftp/main.go | 10 ++-- internal/server/options.go | 22 ++++++++ internal/server/server.go | 103 ++++++++++++++++++++++++++++++++----- 5 files changed, 119 insertions(+), 21 deletions(-) create mode 100644 internal/server/options.go diff --git a/.gitignore b/.gitignore index 3bd1a16..22c87b5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ testFiles/ out/ sha512sums.txt pubkey.pem +privkey.pem \ No newline at end of file diff --git a/Makefile b/Makefile index f7c7d6c..d0453d4 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ server: go run cmd/uftp/main.go server test: - go run cmd/uftp/main.go client testFiles/testFile 0.0.0.0 + go run cmd/uftp/main.go client testFile 0.0.0.0 win: - GOOS=windows GOARCH=amd64 go build -o bin/app-amd64.exe cmd/uftp/main.go \ No newline at end of file + GOOS=windows GOARCH=amd64 go build -o bin/app-amd64.exe cmd/uftp/main.go diff --git a/cmd/uftp/main.go b/cmd/uftp/main.go index 433f403..740f1bb 100644 --- a/cmd/uftp/main.go +++ b/cmd/uftp/main.go @@ -9,11 +9,11 @@ import ( func main() { if os.Args[1] == "server" { - server, err := server.New() - if err != nil { - panic(err) - } - err = server.SavePublicKeyPem() + server, err := server.New(func(o *server.Options) { + o.SavePrivKey = false + o.LoadPrivkey = true + o.PrivKeyPath = "privkey.pem" + }) if err != nil { panic(err) } diff --git a/internal/server/options.go b/internal/server/options.go new file mode 100644 index 0000000..f709a49 --- /dev/null +++ b/internal/server/options.go @@ -0,0 +1,22 @@ +package server + +type Options struct { + Address string + Datapath string + LoadPrivkey bool + PrivKeyPath string + PubKeyPath string + SavePubKey bool + SavePrivKey bool +} + +func NewDefaultOptions() *Options { + return &Options{ + Address: "0.0.0.0", + Datapath: "./testFiles/", + LoadPrivkey: false, + SavePrivKey: false, + SavePubKey: true, + PubKeyPath: "pubkey.pem", + } +} diff --git a/internal/server/server.go b/internal/server/server.go index 553f7bf..0c0809f 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -8,10 +8,12 @@ import ( "encoding/hex" "encoding/pem" "errors" + "fmt" "io" "net" "os" "os/signal" + "path/filepath" "sync" "time" @@ -29,29 +31,87 @@ type info struct { } type Server struct { - sessions map[common.SessionID]*info - mu sync.Mutex - rsa *rsa.PrivateKey + sessions map[common.SessionID]*info + mu sync.Mutex + rsa *rsa.PrivateKey + options *Options + parentFilePath string } -func New() (*Server, error) { - key, err := rsa.GenerateKey(rand.Reader, 4096) +func New(opts ...func(*Options)) (*Server, error) { + options := NewDefaultOptions() + + for _, opt := range opts { + opt(options) + } + + var key *rsa.PrivateKey + var err error + if options.LoadPrivkey { + privKey, err := os.ReadFile(options.PrivKeyPath) + if err != nil { + return nil, err + } + + block, _ := pem.Decode(privKey) + key, _ = x509.ParsePKCS1PrivateKey(block.Bytes) + } else { + key, err = rsa.GenerateKey(rand.Reader, 4096) + if err != nil { + return nil, err + } + } + + parentFilePath, err := filepath.Abs(options.Datapath) if err != nil { return nil, err } + server := &Server{ + sessions: make(map[common.SessionID]*info), + rsa: key, + options: options, + parentFilePath: parentFilePath, + } + + if options.SavePubKey { + err = server.SavePublicKeyPem() + if err != nil { + return nil, err + } + } + + if options.SavePrivKey { + err = server.SavePrivateKeyPem() + if err != nil { + return nil, err + } + } + log.SetFormatter(&log.TextFormatter{ ForceColors: true, }) - return &Server{ - sessions: make(map[common.SessionID]*info), - rsa: key, - }, nil + return server, nil +} + +func (server *Server) SavePrivateKeyPem() error { + file, err := os.Create(server.options.PrivKeyPath) + if err != nil { + return err + } + + defer file.Close() + privateKeyPEM := &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(server.rsa), + } + pem.Encode(file, privateKeyPEM) + return nil } func (server *Server) SavePublicKeyPem() error { - file, err := os.Create("pubkey.pem") + file, err := os.Create(server.options.PubKeyPath) if err != nil { return err } @@ -179,9 +239,23 @@ func (server *Server) sendPTE(conn *net.UDPConn, addr *net.UDPAddr, pck *common. return } - fi, err := os.Stat(path) + file := filepath.Join(server.parentFilePath, path) + file = filepath.Clean(file) + + matched, err := filepath.Match(fmt.Sprintf("%v\\*", server.parentFilePath), file) + + if err != nil || !matched { + log.WithFields(log.Fields{ + "ParentFilePath": server.parentFilePath, + "RequestedFilePath": path, + "CleanedFilePath": file, + }).WithError(err).Warn("Requesting File out of Path") + return + } + + fi, err := os.Stat(file) if err != nil { - log.WithError(err).WithField("File Path", path).Error("Unable to open File") + log.WithError(err).WithField("File Path", file).Error("Unable to open File") return } @@ -192,7 +266,7 @@ func (server *Server) sendPTE(conn *net.UDPConn, addr *net.UDPAddr, pck *common. server.mu.Lock() if info, ok := server.sessions[pck.Sid]; ok { - info.path = path + info.path = file info.lastSync = ptePck.Sync info.lastPckSend = ptePck.Flag server.mu.Unlock() @@ -321,6 +395,7 @@ func (server *Server) handleConnection(conn net.Conn) { server.mu.Unlock() conn.Write([]byte("Yep")) conn.Close() + log.WithField("SessionID", hex.EncodeToString(rsaPck.Sid[:])).Info("Started Session") } func (server *Server) startManagement() { @@ -340,7 +415,7 @@ func (server *Server) startManagement() { } func (server *Server) Serve() { - udpAddr, err := net.ResolveUDPAddr("udp", "0.0.0.0:13374") + udpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%v:13374", server.options.Address)) if err != nil { log.Fatal("Could not resolve UDP Address") }