]> Cypherpunks.ru repositories - nncp.git/blobdiff - src/cypherpunks.ru/nncp/toss.go
Forbid any later GNU GPL versions autousage
[nncp.git] / src / cypherpunks.ru / nncp / toss.go
index 2fb4cbb034b47b1c549f92bfda036e6433182a8c..c180ed9554c6c1d6b9c5b4fc4fc068f0df596546 100644 (file)
@@ -1,11 +1,10 @@
 /*
 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
-Copyright (C) 2016-2017 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2016-2019 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, version 3 of the License.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,6 +19,7 @@ package nncp
 
 import (
        "bufio"
+       "bytes"
        "compress/zlib"
        "fmt"
        "io"
@@ -36,6 +36,11 @@ import (
        "github.com/davecgh/go-xdr/xdr2"
        "github.com/dustin/go-humanize"
        "golang.org/x/crypto/blake2b"
+       "golang.org/x/crypto/poly1305"
+)
+
+const (
+       SeenSuffix = ".seen"
 )
 
 func newNotification(fromTo *FromToYAML, subject string) io.Reader {
@@ -47,7 +52,11 @@ func newNotification(fromTo *FromToYAML, subject string) io.Reader {
        ))
 }
 
-func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun bool) bool {
+func (ctx *Ctx) Toss(
+       nodeId *NodeId,
+       nice uint8,
+       dryRun, doSeen, noFile, noFreq, noExec, noTrns bool,
+) bool {
        isBad := false
        for job := range ctx.Jobs(nodeId, TRx) {
                pktName := filepath.Base(job.Fd.Name())
@@ -79,54 +88,80 @@ func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun bool) bool {
                var pkt Pkt
                var err error
                var pktSize int64
+               var pktSizeBlocks int64
                if _, err = xdr.Unmarshal(pipeR, &pkt); err != nil {
                        ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "unmarshal")
                        isBad = true
                        goto Closing
                }
-               pktSize = job.Size - PktEncOverhead - PktOverhead
+               pktSize = job.Size - PktEncOverhead - PktOverhead - PktSizeOverhead
+               pktSizeBlocks = pktSize / (EncBlkSize + poly1305.TagSize)
+               if pktSize%(EncBlkSize+poly1305.TagSize) != 0 {
+                       pktSize -= poly1305.TagSize
+               }
+               pktSize -= pktSizeBlocks * poly1305.TagSize
                sds["size"] = strconv.FormatInt(pktSize, 10)
                ctx.LogD("rx", sds, "taken")
                switch pkt.Type {
-               case PktTypeMail:
-                       recipients := string(pkt.Path[:int(pkt.PathLen)])
+               case PktTypeExec:
+                       if noExec {
+                               goto Closing
+                       }
+                       path := bytes.Split(pkt.Path[:int(pkt.PathLen)], []byte{0})
+                       handle := string(path[0])
+                       args := make([]string, 0, len(path)-1)
+                       for _, p := range path[1:] {
+                               args = append(args, string(p))
+                       }
                        sds := SdsAdd(sds, SDS{
-                               "type": "mail",
-                               "dst":  recipients,
+                               "type": "exec",
+                               "dst":  strings.Join(append([]string{handle}, args...), " "),
                        })
                        decompressor, err := zlib.NewReader(pipeR)
                        if err != nil {
                                log.Fatalln(err)
                        }
-                       sendmail := ctx.Neigh[*job.PktEnc.Sender].Sendmail
-                       if len(sendmail) == 0 {
-                               ctx.LogE("rx", SdsAdd(sds, SDS{"err": "No sendmail configured"}), "")
+                       sender := ctx.Neigh[*job.PktEnc.Sender]
+                       cmdline, exists := sender.Exec[handle]
+                       if !exists || len(cmdline) == 0 {
+                               ctx.LogE("rx", SdsAdd(sds, SDS{"err": "No handle found"}), "")
                                isBad = true
                                goto Closing
                        }
                        if !dryRun {
                                cmd := exec.Command(
-                                       sendmail[0],
-                                       append(
-                                               sendmail[1:len(sendmail)],
-                                               strings.Split(recipients, " ")...,
-                                       )...,
+                                       cmdline[0],
+                                       append(cmdline[1:len(cmdline)], args...)...,
+                               )
+                               cmd.Env = append(
+                                       cmd.Env,
+                                       "NNCP_SELF="+ctx.Self.Id.String(),
+                                       "NNCP_SENDER="+sender.Id.String(),
+                                       "NNCP_NICE="+strconv.Itoa(int(pkt.Nice)),
                                )
                                cmd.Stdin = decompressor
                                if err = cmd.Run(); err != nil {
-                                       ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "sendmail")
+                                       ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "handle")
                                        isBad = true
                                        goto Closing
                                }
                        }
                        ctx.LogI("rx", sds, "")
                        if !dryRun {
+                               if doSeen {
+                                       if fd, err := os.Create(job.Fd.Name() + SeenSuffix); err == nil {
+                                               fd.Close()
+                                       }
+                               }
                                if err = os.Remove(job.Fd.Name()); err != nil {
                                        ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "remove")
                                        isBad = true
                                }
                        }
                case PktTypeFile:
+                       if noFile {
+                               goto Closing
+                       }
                        dst := string(pkt.Path[:int(pkt.PathLen)])
                        sds := SdsAdd(sds, SDS{"type": "file", "dst": dst})
                        if filepath.IsAbs(dst) {
@@ -148,21 +183,31 @@ func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun bool) bool {
                        }
                        if !dryRun {
                                tmp, err := ioutil.TempFile(dir, "nncp-file")
-                               sds["tmp"] = tmp.Name()
-                               ctx.LogD("rx", sds, "created")
                                if err != nil {
                                        ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "mktemp")
                                        isBad = true
                                        goto Closing
                                }
+                               sds["tmp"] = tmp.Name()
+                               ctx.LogD("rx", sds, "created")
                                bufW := bufio.NewWriter(tmp)
                                if _, err = io.Copy(bufW, pipeR); err != nil {
                                        ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "copy")
                                        isBad = true
                                        goto Closing
                                }
-                               bufW.Flush()
-                               tmp.Sync()
+                               if err = bufW.Flush(); err != nil {
+                                       tmp.Close()
+                                       ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "copy")
+                                       isBad = true
+                                       goto Closing
+                               }
+                               if err = tmp.Sync(); err != nil {
+                                       tmp.Close()
+                                       ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "copy")
+                                       isBad = true
+                                       goto Closing
+                               }
                                tmp.Close()
                                dstPathOrig := filepath.Join(*incoming, dst)
                                dstPath := dstPathOrig
@@ -187,12 +232,17 @@ func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun bool) bool {
                        }
                        ctx.LogI("rx", sds, "")
                        if !dryRun {
+                               if doSeen {
+                                       if fd, err := os.Create(job.Fd.Name() + SeenSuffix); err == nil {
+                                               fd.Close()
+                                       }
+                               }
                                if err = os.Remove(job.Fd.Name()); err != nil {
                                        ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "remove")
                                        isBad = true
                                }
-                               sendmail := ctx.Neigh[*ctx.SelfId].Sendmail
-                               if ctx.NotifyFile != nil {
+                               sendmail, exists := ctx.Neigh[*ctx.SelfId].Exec["sendmail"]
+                               if exists && len(sendmail) > 0 && ctx.NotifyFile != nil {
                                        cmd := exec.Command(
                                                sendmail[0],
                                                append(sendmail[1:len(sendmail)], ctx.NotifyFile.To)...,
@@ -207,6 +257,9 @@ func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun bool) bool {
                                }
                        }
                case PktTypeFreq:
+                       if noFreq {
+                               goto Closing
+                       }
                        src := string(pkt.Path[:int(pkt.PathLen)])
                        if filepath.IsAbs(src) {
                                ctx.LogE("rx", sds, "non-relative source path")
@@ -233,7 +286,7 @@ func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun bool) bool {
                                if sender.FreqChunked == 0 {
                                        err = ctx.TxFile(
                                                sender,
-                                               job.PktEnc.Nice,
+                                               pkt.Nice,
                                                filepath.Join(*freq, src),
                                                dst,
                                                sender.FreqMinSize,
@@ -241,7 +294,7 @@ func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun bool) bool {
                                } else {
                                        err = ctx.TxFileChunked(
                                                sender,
-                                               job.PktEnc.Nice,
+                                               pkt.Nice,
                                                filepath.Join(*freq, src),
                                                dst,
                                                sender.FreqMinSize,
@@ -256,12 +309,17 @@ func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun bool) bool {
                        }
                        ctx.LogI("rx", sds, "")
                        if !dryRun {
+                               if doSeen {
+                                       if fd, err := os.Create(job.Fd.Name() + SeenSuffix); err == nil {
+                                               fd.Close()
+                                       }
+                               }
                                if err = os.Remove(job.Fd.Name()); err != nil {
                                        ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "remove")
                                        isBad = true
                                }
-                               if ctx.NotifyFreq != nil {
-                                       sendmail := ctx.Neigh[*ctx.SelfId].Sendmail
+                               sendmail, exists := ctx.Neigh[*ctx.SelfId].Exec["sendmail"]
+                               if exists && len(sendmail) > 0 && ctx.NotifyFreq != nil {
                                        cmd := exec.Command(
                                                sendmail[0],
                                                append(sendmail[1:len(sendmail)], ctx.NotifyFreq.To)...,
@@ -275,6 +333,9 @@ func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun bool) bool {
                                }
                        }
                case PktTypeTrns:
+                       if noTrns {
+                               goto Closing
+                       }
                        dst := new([blake2b.Size256]byte)
                        copy(dst[:], pkt.Path[:int(pkt.PathLen)])
                        nodeId := NodeId(*dst)
@@ -295,6 +356,11 @@ func (ctx *Ctx) Toss(nodeId *NodeId, nice uint8, dryRun bool) bool {
                        }
                        ctx.LogI("rx", sds, "")
                        if !dryRun {
+                               if doSeen {
+                                       if fd, err := os.Create(job.Fd.Name() + SeenSuffix); err == nil {
+                                               fd.Close()
+                                       }
+                               }
                                if err = os.Remove(job.Fd.Name()); err != nil {
                                        ctx.LogE("rx", SdsAdd(sds, SDS{"err": err}), "remove")
                                        isBad = true