/*
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
import (
"bufio"
+ "bytes"
"compress/zlib"
"fmt"
"io"
"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 {
))
}
-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())
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) {
}
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
}
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)...,
}
}
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")
if sender.FreqChunked == 0 {
err = ctx.TxFile(
sender,
- job.PktEnc.Nice,
+ pkt.Nice,
filepath.Join(*freq, src),
dst,
sender.FreqMinSize,
} else {
err = ctx.TxFileChunked(
sender,
- job.PktEnc.Nice,
+ pkt.Nice,
filepath.Join(*freq, src),
dst,
sender.FreqMinSize,
}
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)...,
}
}
case PktTypeTrns:
+ if noTrns {
+ goto Closing
+ }
dst := new([blake2b.Size256]byte)
copy(dst[:], pkt.Path[:int(pkt.PathLen)])
nodeId := NodeId(*dst)
}
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