]> Cypherpunks.ru repositories - nncp.git/commitdiff
nncp-exec -nocompress/-use-tmp options
authorSergey Matveev <stargrave@stargrave.org>
Wed, 6 Jan 2021 21:25:03 +0000 (00:25 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Wed, 6 Jan 2021 21:27:36 +0000 (00:27 +0300)
doc/cmds.texi
doc/news.ru.texi
doc/news.texi
doc/pkt.texi
src/cmd/nncp-exec/main.go
src/cmd/nncp-pkt/main.go
src/pkt.go
src/toss.go
src/toss_test.go
src/tx.go

index 2fb0374cbf235eb3ceb04febf7d162834f6f50c3..75835acb5af4d56ea8cd4fcc80a82d8e208acc29 100644 (file)
@@ -262,12 +262,14 @@ uucp      stream  tcp6    nowait  nncpuser        /usr/local/bin/nncp-daemon      nncp-daemon -quiet -
 @section nncp-exec
 
 @example
-$ nncp-exec [options] NODE HANDLE [ARG0 ARG1 ...]
+$ nncp-exec [options] [-use-tmp] [-nocompress] NODE HANDLE [ARG0 ARG1 ...]
 @end example
 
 Send execution command to @option{NODE} for specified @option{HANDLE}.
-Body is read from stdin and compressed. After receiving, remote side
-will execute specified @ref{CfgExec, handle} command with @option{ARG*}
+Body is read from stdin (either into memory, or into encrypted temporary
+file if @option{-use-tmp} is specified) and compressed (unless
+@option{-nocompress} is specified}. After receiving, remote side will
+execute specified @ref{CfgExec, handle} command with @option{ARG*}
 appended and decompressed body fed to command's stdin.
 
 For example, if remote side has following configuration file for your
@@ -295,7 +297,7 @@ If @ref{CfgNotify, notification} is enabled on the remote side for exec
 handles, then it will sent simple letter after successful command
 execution with its output in message body.
 
-@strong{Pay attention} that packet generated with this command can not
+@strong{Pay attention} that packet generated with this command won't be
 be chunked.
 
 @node nncp-file
index f9ff365817f6487713f7c97651e81abf640454df..10c3f51db4874622202d12faf7384739f4c43e85 100644 (file)
 @item
 У команды @command{nncp-rm} появились @option{-dryrun} и @option{-older} опции.
 
+@item
+У команды @command{nncp-exec} появились @option{-use-tmp} и
+@option{-nocompress} опции. Несжатые пакеты не совместимы с предыдущими
+версиями NNCP.
+
 @item
 Обновлены зависимые библиотеки.
 
index 30f1c99221e12225bb78b0c83b685a9fe9de4ba3..cb232e4ff7f4a0b8963e52a8a4dacf72be8cbe97 100644 (file)
@@ -14,6 +14,11 @@ Bugfixes in @command{nncp-call(er)}/@command{nncp-daemon},
 @item
 @command{nncp-rm} has @option{-dryrun} and @option{-older} options now.
 
+@item
+@command{nncp-exec} has @option{-use-tmp} and @option{-nocompress}
+options now. Uncompressed packets are not compatible with previous NNCP
+versions.
+
 @item
 Updated dependencies.
 
index 33c2f2810b9bc178f669217ff4e99401e86fe2db..93841e107234eb6e82e8e1abf71be7c18b50a4df 100644 (file)
@@ -31,7 +31,7 @@ drive.
     @verb{|N N C P P 0x00 0x00 0x03|}
 @item Payload type @tab
     unsigned integer @tab
-    0 (file), 1 (freq), 2 (exec), 3 (transition)
+    0 (file), 1 (freq), 2 (exec), 3 (transition), 4 (exec-fat)
 @item Niceness @tab
     unsigned integer @tab
     1-255, preferred packet @ref{Niceness, niceness} level
@@ -61,6 +61,7 @@ Depending on the packet's type, payload could store:
 @item Destination path for freq
 @item @url{https://facebook.github.io/zstd/, Zstandard} compressed exec body
 @item Whole encrypted packet we need to relay on
+@item Uncompressed exec body
 @end itemize
 
 Also depending on packet's type, niceness level means:
index d0cb537f543375e8dc47e3ded962f4683468c464..fe559ba2bdc299187dd3e2fcf7cde95e3b2281d6 100644 (file)
@@ -37,6 +37,8 @@ func usage() {
 
 func main() {
        var (
+               useTmp       = flag.Bool("use-tmp", false, "Use temporary file, instead of memory buffer")
+               noCompress   = flag.Bool("nocompress", false, "Do not compress input data")
                cfgPath      = flag.String("cfg", nncp.DefaultCfgPath, "Path to configuration file")
                niceRaw      = flag.String("nice", nncp.NicenessFmt(nncp.DefaultNiceExec), "Outbound packet niceness")
                replyNiceRaw = flag.String("replynice", nncp.NicenessFmt(nncp.DefaultNiceFile), "Possible reply packet niceness")
@@ -106,6 +108,8 @@ func main() {
                flag.Args()[2:],
                bufio.NewReader(os.Stdin),
                int64(*minSize)*1024,
+               *useTmp,
+               *noCompress,
        ); err != nil {
                log.Fatalln(err)
        }
index 0e4d4295eb386ef07e41849a03600dda60bd99ad..145b30bcb5485c32b1710c7b6bb9e7de545bdab6 100644 (file)
@@ -105,12 +105,14 @@ func main() {
                        payloadType = "file request"
                case nncp.PktTypeExec:
                        payloadType = "exec"
+               case nncp.PktTypeExecFat:
+                       payloadType = "exec uncompressed"
                case nncp.PktTypeTrns:
                        payloadType = "transitional"
                }
                var path string
                switch pkt.Type {
-               case nncp.PktTypeExec:
+               case nncp.PktTypeExec, nncp.PktTypeExecFat:
                        path = string(bytes.Replace(
                                pkt.Path[:pkt.PathLen],
                                []byte{0},
index 5fdaad7bbdaeb85c3e5fd92a7782da0da953a597..4dea1bf3713ab939c0f17fa8c37b267ebd82a9f2 100644 (file)
@@ -40,10 +40,11 @@ const (
        EncBlkSize = 128 * (1 << 10)
        KDFXOFSize = chacha20poly1305.KeySize * 2
 
-       PktTypeFile PktType = iota
-       PktTypeFreq PktType = iota
-       PktTypeExec PktType = iota
-       PktTypeTrns PktType = iota
+       PktTypeFile    PktType = iota
+       PktTypeFreq    PktType = iota
+       PktTypeExec    PktType = iota
+       PktTypeTrns    PktType = iota
+       PktTypeExecFat PktType = iota
 
        MaxPathSize = 1<<8 - 1
 
index ecc60ed2efacc4e89c9123a7d247912aab4f8cfc..f70ffd3dd7674051af5cc74c5a7d5b0a8061ce3e 100644 (file)
@@ -126,7 +126,7 @@ func (ctx *Ctx) Toss(
                sds["size"] = pktSize
                ctx.LogD("rx", sds, "taken")
                switch pkt.Type {
-               case PktTypeExec:
+               case PktTypeExec, PktTypeExecFat:
                        if noExec {
                                goto Closing
                        }
@@ -148,8 +148,10 @@ func (ctx *Ctx) Toss(
                                isBad = true
                                goto Closing
                        }
-                       if err = decompressor.Reset(pipeR); err != nil {
-                               log.Fatalln(err)
+                       if pkt.Type == PktTypeExec {
+                               if err = decompressor.Reset(pipeR); err != nil {
+                                       log.Fatalln(err)
+                               }
                        }
                        if !dryRun {
                                cmd := exec.Command(
@@ -162,7 +164,11 @@ func (ctx *Ctx) Toss(
                                        "NNCP_SENDER="+sender.Id.String(),
                                        "NNCP_NICE="+strconv.Itoa(int(pkt.Nice)),
                                )
-                               cmd.Stdin = decompressor
+                               if pkt.Type == PktTypeExec {
+                                       cmd.Stdin = decompressor
+                               } else {
+                                       cmd.Stdin = pipeR
+                               }
                                output, err := cmd.Output()
                                if err != nil {
                                        ctx.LogE("rx", sds, err, "handle")
index d269141cc5ca199b015f5e50e74375178ab0a6c9..8a16dd94512f184c87e60aef65e88f30c0f629be 100644 (file)
@@ -99,6 +99,8 @@ func TestTossExec(t *testing.T) {
                                []string{"arg0", "arg1"},
                                strings.NewReader("BODY\n"),
                                1<<15,
+                               false,
+                               false,
                        ); err != nil {
                                t.Error(err)
                                return false
@@ -449,7 +451,6 @@ func TestTossTrns(t *testing.T) {
                                Magic:   MagicNNCPPv3,
                                Type:    PktTypeTrns,
                                PathLen: blake2b.Size256,
-                               Path:    new([MaxPathSize]byte),
                        }
                        copy(pktTrans.Path[:], nodeOur.Id[:])
                        var dst bytes.Buffer
index d00ba6165890b2d2e3f35eed2974e060bd7bfbe7..3352f861a8465d63e95cfdacdce8a724fb203db5 100644 (file)
--- a/src/tx.go
+++ b/src/tx.go
@@ -131,49 +131,63 @@ type DummyCloser struct{}
 
 func (dc DummyCloser) Close() error { return nil }
 
-func prepareTxFile(srcPath string) (reader io.Reader, closer io.Closer, fileSize int64, archived bool, rerr error) {
-       if srcPath == "-" {
-               // Read content from stdin, saving to temporary file, encrypting
-               // on the fly
-               src, err := ioutil.TempFile("", "nncp-file")
-               if err != nil {
-                       rerr = err
-                       return
-               }
-               os.Remove(src.Name()) // #nosec G104
-               tmpW := bufio.NewWriter(src)
-               tmpKey := make([]byte, chacha20poly1305.KeySize)
-               if _, rerr = rand.Read(tmpKey[:]); rerr != nil {
-                       return
-               }
-               aead, err := chacha20poly1305.New(tmpKey)
-               if err != nil {
-                       rerr = err
-                       return
-               }
-               nonce := make([]byte, aead.NonceSize())
-               written, err := aeadProcess(aead, nonce, true, bufio.NewReader(os.Stdin), tmpW)
-               if err != nil {
-                       rerr = err
-                       return
-               }
-               fileSize = int64(written)
-               if err = tmpW.Flush(); err != nil {
-                       rerr = err
-                       return
-               }
-               if _, err = src.Seek(0, io.SeekStart); err != nil {
-                       rerr = err
-                       return
+func throughTmpFile(r io.Reader) (
+       reader io.Reader,
+       closer io.Closer,
+       fileSize int64,
+       rerr error,
+) {
+       src, err := ioutil.TempFile("", "nncp-file")
+       if err != nil {
+               rerr = err
+               return
+       }
+       os.Remove(src.Name()) // #nosec G104
+       tmpW := bufio.NewWriter(src)
+       tmpKey := make([]byte, chacha20poly1305.KeySize)
+       if _, rerr = rand.Read(tmpKey[:]); rerr != nil {
+               return
+       }
+       aead, err := chacha20poly1305.New(tmpKey)
+       if err != nil {
+               rerr = err
+               return
+       }
+       nonce := make([]byte, aead.NonceSize())
+       written, err := aeadProcess(aead, nonce, true, r, tmpW)
+       if err != nil {
+               rerr = err
+               return
+       }
+       fileSize = int64(written)
+       if err = tmpW.Flush(); err != nil {
+               rerr = err
+               return
+       }
+       if _, err = src.Seek(0, io.SeekStart); err != nil {
+               rerr = err
+               return
+       }
+       r, w := io.Pipe()
+       go func() {
+               if _, err := aeadProcess(aead, nonce, false, bufio.NewReader(src), w); err != nil {
+                       w.CloseWithError(err) // #nosec G104
                }
-               r, w := io.Pipe()
-               go func() {
-                       if _, err := aeadProcess(aead, nonce, false, bufio.NewReader(src), w); err != nil {
-                               w.CloseWithError(err) // #nosec G104
-                       }
-               }()
-               reader = r
-               closer = src
+       }()
+       reader = r
+       closer = src
+       return
+}
+
+func prepareTxFile(srcPath string) (
+       reader io.Reader,
+       closer io.Closer,
+       fileSize int64,
+       archived bool,
+       rerr error,
+) {
+       if srcPath == "-" {
+               reader, closer, fileSize, rerr = throughTmpFile(bufio.NewReader(os.Stdin))
                return
        }
 
@@ -481,33 +495,94 @@ func (ctx *Ctx) TxExec(
        args []string,
        in io.Reader,
        minSize int64,
+       useTmp bool,
+       noCompress bool,
 ) error {
        path := make([][]byte, 0, 1+len(args))
        path = append(path, []byte(handle))
        for _, arg := range args {
                path = append(path, []byte(arg))
        }
-       pkt, err := NewPkt(PktTypeExec, replyNice, bytes.Join(path, []byte{0}))
-       if err != nil {
-               return err
+       pktType := PktTypeExec
+       if noCompress {
+               pktType = PktTypeExecFat
        }
-       var compressed bytes.Buffer
-       compressor, err := zstd.NewWriter(
-               &compressed,
-               zstd.WithEncoderLevel(zstd.SpeedDefault),
-       )
+       pkt, err := NewPkt(pktType, replyNice, bytes.Join(path, []byte{0}))
        if err != nil {
                return err
        }
-       if _, err = io.Copy(compressor, in); err != nil {
-               compressor.Close() // #nosec G104
-               return err
+       var size int64
+
+       if !noCompress && !useTmp {
+               var compressed bytes.Buffer
+               compressor, err := zstd.NewWriter(
+                       &compressed,
+                       zstd.WithEncoderLevel(zstd.SpeedDefault),
+               )
+               if err != nil {
+                       return err
+               }
+               if _, err = io.Copy(compressor, in); err != nil {
+                       compressor.Close() // #nosec G104
+                       return err
+               }
+               if err = compressor.Close(); err != nil {
+                       return err
+               }
+               size = int64(compressed.Len())
+               _, err = ctx.Tx(node, pkt, nice, size, minSize, &compressed, handle)
        }
-       if err = compressor.Close(); err != nil {
-               return err
+       if noCompress && !useTmp {
+               var data bytes.Buffer
+               if _, err = io.Copy(&data, in); err != nil {
+                       return err
+               }
+               size = int64(data.Len())
+               _, err = ctx.Tx(node, pkt, nice, size, minSize, &data, handle)
        }
-       size := int64(compressed.Len())
-       _, err = ctx.Tx(node, pkt, nice, size, minSize, &compressed, handle)
+       if !noCompress && useTmp {
+               r, w := io.Pipe()
+               compressor, err := zstd.NewWriter(w, zstd.WithEncoderLevel(zstd.SpeedDefault))
+               if err != nil {
+                       return err
+               }
+               copyErr := make(chan error)
+               go func() {
+                       _, err := io.Copy(compressor, in)
+                       if err != nil {
+                               compressor.Close() // #nosec G104
+                               copyErr <- err
+                       }
+                       err = compressor.Close()
+                       w.Close()
+                       copyErr <- err
+               }()
+               tmpReader, closer, fileSize, err := throughTmpFile(r)
+               if closer != nil {
+                       defer closer.Close()
+               }
+               if err != nil {
+                       return err
+               }
+               err = <-copyErr
+               if err != nil {
+                       return err
+               }
+               size = fileSize
+               _, err = ctx.Tx(node, pkt, nice, size, minSize, tmpReader, handle)
+       }
+       if noCompress && useTmp {
+               tmpReader, closer, fileSize, err := throughTmpFile(in)
+               if closer != nil {
+                       defer closer.Close()
+               }
+               if err != nil {
+                       return err
+               }
+               size = fileSize
+               _, err = ctx.Tx(node, pkt, nice, size, minSize, tmpReader, handle)
+       }
+
        sds := SDS{
                "type":      "exec",
                "node":      node.Id,