]> Cypherpunks.ru repositories - nncp.git/blob - src/toss.go
Merge branch 'develop'
[nncp.git] / src / toss.go
1 /*
2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2021 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 package nncp
19
20 import (
21         "bufio"
22         "bytes"
23         "encoding/base64"
24         "errors"
25         "fmt"
26         "io"
27         "io/ioutil"
28         "log"
29         "mime"
30         "os"
31         "os/exec"
32         "path"
33         "path/filepath"
34         "strconv"
35         "strings"
36         "time"
37
38         xdr "github.com/davecgh/go-xdr/xdr2"
39         "github.com/dustin/go-humanize"
40         "github.com/klauspost/compress/zstd"
41         "golang.org/x/crypto/blake2b"
42         "golang.org/x/crypto/poly1305"
43 )
44
45 const (
46         SeenSuffix = ".seen"
47 )
48
49 func newNotification(fromTo *FromToJSON, subject string, body []byte) io.Reader {
50         lines := []string{
51                 "From: " + fromTo.From,
52                 "To: " + fromTo.To,
53                 "Subject: " + mime.BEncoding.Encode("UTF-8", subject),
54         }
55         if len(body) > 0 {
56                 lines = append(
57                         lines,
58                         "MIME-Version: 1.0",
59                         "Content-Type: text/plain; charset=utf-8",
60                         "Content-Transfer-Encoding: base64",
61                         "",
62                         base64.StdEncoding.EncodeToString(body),
63                 )
64         }
65         return strings.NewReader(strings.Join(lines, "\n"))
66 }
67
68 func (ctx *Ctx) Toss(
69         nodeId *NodeId,
70         nice uint8,
71         dryRun, doSeen, noFile, noFreq, noExec, noTrns bool,
72 ) bool {
73         dirLock, err := ctx.LockDir(nodeId, "toss")
74         if err != nil {
75                 return false
76         }
77         defer ctx.UnlockDir(dirLock)
78         isBad := false
79         sendmail := ctx.Neigh[*ctx.SelfId].Exec["sendmail"]
80         decompressor, err := zstd.NewReader(nil)
81         if err != nil {
82                 panic(err)
83         }
84         defer decompressor.Close()
85         for job := range ctx.Jobs(nodeId, TRx) {
86                 pktName := filepath.Base(job.Path)
87                 les := LEs{
88                         {"Node", job.PktEnc.Sender},
89                         {"Pkt", pktName},
90                         {"Nice", int(job.PktEnc.Nice)},
91                 }
92                 if job.PktEnc.Nice > nice {
93                         ctx.LogD("rx-too-nice", les, func(les LEs) string {
94                                 return fmt.Sprintf(
95                                         "Tossing %s/%s: too nice: %s",
96                                         ctx.NodeName(job.PktEnc.Sender), pktName,
97                                         NicenessFmt(job.PktEnc.Nice),
98                                 )
99                         })
100                         continue
101                 }
102                 fd, err := os.Open(job.Path)
103                 if err != nil {
104                         ctx.LogE("rx-open", les, err, func(les LEs) string {
105                                 return fmt.Sprintf(
106                                         "Tossing %s/%s: opening %s",
107                                         ctx.NodeName(job.PktEnc.Sender), pktName, job.Path,
108                                 )
109                         })
110                         isBad = true
111                         continue
112                 }
113
114                 pipeR, pipeW := io.Pipe()
115                 go func(job Job) error {
116                         pipeWB := bufio.NewWriter(pipeW)
117                         _, _, err := PktEncRead(ctx.Self, ctx.Neigh, bufio.NewReader(fd), pipeWB)
118                         fd.Close() // #nosec G104
119                         if err != nil {
120                                 return pipeW.CloseWithError(err)
121                         }
122                         if err = pipeWB.Flush(); err != nil {
123                                 return pipeW.CloseWithError(err)
124                         }
125                         return pipeW.Close()
126                 }(job)
127                 var pkt Pkt
128                 var pktSize int64
129                 var pktSizeBlocks int64
130                 if _, err = xdr.Unmarshal(pipeR, &pkt); err != nil {
131                         ctx.LogE("rx-unmarshal", les, err, func(les LEs) string {
132                                 return fmt.Sprintf(
133                                         "Tossing %s/%s: unmarshal",
134                                         ctx.NodeName(job.PktEnc.Sender), pktName,
135                                 )
136                         })
137                         isBad = true
138                         goto Closing
139                 }
140                 pktSize = job.Size - PktEncOverhead - PktOverhead - PktSizeOverhead
141                 pktSizeBlocks = pktSize / (EncBlkSize + poly1305.TagSize)
142                 if pktSize%(EncBlkSize+poly1305.TagSize) != 0 {
143                         pktSize -= poly1305.TagSize
144                 }
145                 pktSize -= pktSizeBlocks * poly1305.TagSize
146                 les = append(les, LE{"Size", pktSize})
147                 ctx.LogD("rx", les, func(les LEs) string {
148                         return fmt.Sprintf(
149                                 "Tossing %s/%s (%s)",
150                                 ctx.NodeName(job.PktEnc.Sender), pktName,
151                                 humanize.IBytes(uint64(pktSize)),
152                         )
153                 })
154
155                 switch pkt.Type {
156                 case PktTypeExec, PktTypeExecFat:
157                         if noExec {
158                                 goto Closing
159                         }
160                         path := bytes.Split(pkt.Path[:int(pkt.PathLen)], []byte{0})
161                         handle := string(path[0])
162                         args := make([]string, 0, len(path)-1)
163                         for _, p := range path[1:] {
164                                 args = append(args, string(p))
165                         }
166                         argsStr := strings.Join(append([]string{handle}, args...), " ")
167                         les = append(les, LE{"Type", "exec"}, LE{"Dst", argsStr})
168                         sender := ctx.Neigh[*job.PktEnc.Sender]
169                         cmdline, exists := sender.Exec[handle]
170                         if !exists || len(cmdline) == 0 {
171                                 ctx.LogE(
172                                         "rx-no-handle", les, errors.New("No handle found"),
173                                         func(les LEs) string {
174                                                 return fmt.Sprintf(
175                                                         "Tossing exec %s/%s (%s): %s",
176                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
177                                                         humanize.IBytes(uint64(pktSize)), argsStr,
178                                                 )
179                                         },
180                                 )
181                                 isBad = true
182                                 goto Closing
183                         }
184                         if pkt.Type == PktTypeExec {
185                                 if err = decompressor.Reset(pipeR); err != nil {
186                                         log.Fatalln(err)
187                                 }
188                         }
189                         if !dryRun {
190                                 cmd := exec.Command(cmdline[0], append(cmdline[1:], args...)...)
191                                 cmd.Env = append(
192                                         cmd.Env,
193                                         "NNCP_SELF="+ctx.Self.Id.String(),
194                                         "NNCP_SENDER="+sender.Id.String(),
195                                         "NNCP_NICE="+strconv.Itoa(int(pkt.Nice)),
196                                 )
197                                 if pkt.Type == PktTypeExec {
198                                         cmd.Stdin = decompressor
199                                 } else {
200                                         cmd.Stdin = pipeR
201                                 }
202                                 output, err := cmd.Output()
203                                 if err != nil {
204                                         ctx.LogE("rx-hande", les, err, func(les LEs) string {
205                                                 return fmt.Sprintf(
206                                                         "Tossing exec %s/%s (%s): %s: handling",
207                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
208                                                         humanize.IBytes(uint64(pktSize)), argsStr,
209                                                 )
210                                         })
211                                         isBad = true
212                                         goto Closing
213                                 }
214                                 if len(sendmail) > 0 && ctx.NotifyExec != nil {
215                                         notify, exists := ctx.NotifyExec[sender.Name+"."+handle]
216                                         if !exists {
217                                                 notify, exists = ctx.NotifyExec["*."+handle]
218                                         }
219                                         if exists {
220                                                 cmd := exec.Command(
221                                                         sendmail[0],
222                                                         append(sendmail[1:], notify.To)...,
223                                                 )
224                                                 cmd.Stdin = newNotification(notify, fmt.Sprintf(
225                                                         "Exec from %s: %s", sender.Name, argsStr,
226                                                 ), output)
227                                                 if err = cmd.Run(); err != nil {
228                                                         ctx.LogE("rx-notify", les, err, func(les LEs) string {
229                                                                 return fmt.Sprintf(
230                                                                         "Tossing exec %s/%s (%s): %s: notifying",
231                                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
232                                                                         humanize.IBytes(uint64(pktSize)), argsStr,
233                                                                 )
234                                                         })
235                                                 }
236                                         }
237                                 }
238                         }
239                         ctx.LogI("rx", les, func(les LEs) string {
240                                 return fmt.Sprintf(
241                                         "Got exec from %s to %s (%s)",
242                                         ctx.NodeName(job.PktEnc.Sender), argsStr,
243                                         humanize.IBytes(uint64(pktSize)),
244                                 )
245                         })
246                         if !dryRun {
247                                 if doSeen {
248                                         if fd, err := os.Create(job.Path + SeenSuffix); err == nil {
249                                                 fd.Close() // #nosec G104
250                                         }
251                                 }
252                                 if err = os.Remove(job.Path); err != nil {
253                                         ctx.LogE("rx-notify", les, err, func(les LEs) string {
254                                                 return fmt.Sprintf(
255                                                         "Tossing exec %s/%s (%s): %s: notifying",
256                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
257                                                         humanize.IBytes(uint64(pktSize)), argsStr,
258                                                 )
259                                         })
260                                         isBad = true
261                                 } else if ctx.HdrUsage {
262                                         os.Remove(job.Path + HdrSuffix)
263                                 }
264                         }
265
266                 case PktTypeFile:
267                         if noFile {
268                                 goto Closing
269                         }
270                         dst := string(pkt.Path[:int(pkt.PathLen)])
271                         les = append(les, LE{"Type", "file"}, LE{"Dst", dst})
272                         if filepath.IsAbs(dst) {
273                                 ctx.LogE(
274                                         "rx-non-rel", les, errors.New("non-relative destination path"),
275                                         func(les LEs) string {
276                                                 return fmt.Sprintf(
277                                                         "Tossing file %s/%s (%s): %s",
278                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
279                                                         humanize.IBytes(uint64(pktSize)), dst,
280                                                 )
281                                         },
282                                 )
283                                 isBad = true
284                                 goto Closing
285                         }
286                         incoming := ctx.Neigh[*job.PktEnc.Sender].Incoming
287                         if incoming == nil {
288                                 ctx.LogE(
289                                         "rx-no-incoming", les, errors.New("incoming is not allowed"),
290                                         func(les LEs) string {
291                                                 return fmt.Sprintf(
292                                                         "Tossing file %s/%s (%s): %s",
293                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
294                                                         humanize.IBytes(uint64(pktSize)), dst,
295                                                 )
296                                         },
297                                 )
298                                 isBad = true
299                                 goto Closing
300                         }
301                         dir := filepath.Join(*incoming, path.Dir(dst))
302                         if err = os.MkdirAll(dir, os.FileMode(0777)); err != nil {
303                                 ctx.LogE("rx-mkdir", les, err, func(les LEs) string {
304                                         return fmt.Sprintf(
305                                                 "Tossing file %s/%s (%s): %s: mkdir",
306                                                 ctx.NodeName(job.PktEnc.Sender), pktName,
307                                                 humanize.IBytes(uint64(pktSize)), dst,
308                                         )
309                                 })
310                                 isBad = true
311                                 goto Closing
312                         }
313                         if !dryRun {
314                                 tmp, err := TempFile(dir, "file")
315                                 if err != nil {
316                                         ctx.LogE("rx-mktemp", les, err, func(les LEs) string {
317                                                 return fmt.Sprintf(
318                                                         "Tossing file %s/%s (%s): %s: mktemp",
319                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
320                                                         humanize.IBytes(uint64(pktSize)), dst,
321                                                 )
322                                         })
323                                         isBad = true
324                                         goto Closing
325                                 }
326                                 les = append(les, LE{"Tmp", tmp.Name()})
327                                 ctx.LogD("rx-tmp-created", les, func(les LEs) string {
328                                         return fmt.Sprintf(
329                                                 "Tossing file %s/%s (%s): %s: created: %s",
330                                                 ctx.NodeName(job.PktEnc.Sender), pktName,
331                                                 humanize.IBytes(uint64(pktSize)), dst, tmp.Name(),
332                                         )
333                                 })
334                                 bufW := bufio.NewWriter(tmp)
335                                 if _, err = CopyProgressed(
336                                         bufW, pipeR, "Rx file",
337                                         append(les, LE{"FullSize", pktSize}),
338                                         ctx.ShowPrgrs,
339                                 ); err != nil {
340                                         ctx.LogE("rx-copy", les, err, func(les LEs) string {
341                                                 return fmt.Sprintf(
342                                                         "Tossing file %s/%s (%s): %s: copying",
343                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
344                                                         humanize.IBytes(uint64(pktSize)), dst,
345                                                 )
346                                         })
347                                         isBad = true
348                                         goto Closing
349                                 }
350                                 if err = bufW.Flush(); err != nil {
351                                         tmp.Close() // #nosec G104
352                                         ctx.LogE("rx-flush", les, err, func(les LEs) string {
353                                                 return fmt.Sprintf(
354                                                         "Tossing file %s/%s (%s): %s: flushing",
355                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
356                                                         humanize.IBytes(uint64(pktSize)), dst,
357                                                 )
358                                         })
359                                         isBad = true
360                                         goto Closing
361                                 }
362                                 if err = tmp.Sync(); err != nil {
363                                         tmp.Close() // #nosec G104
364                                         ctx.LogE("rx-sync", les, err, func(les LEs) string {
365                                                 return fmt.Sprintf(
366                                                         "Tossing file %s/%s (%s): %s: syncing",
367                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
368                                                         humanize.IBytes(uint64(pktSize)), dst,
369                                                 )
370                                         })
371                                         isBad = true
372                                         goto Closing
373                                 }
374                                 if err = tmp.Close(); err != nil {
375                                         ctx.LogE("rx-close", les, err, func(les LEs) string {
376                                                 return fmt.Sprintf(
377                                                         "Tossing file %s/%s (%s): %s: closing",
378                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
379                                                         humanize.IBytes(uint64(pktSize)), dst,
380                                                 )
381                                         })
382                                         isBad = true
383                                         goto Closing
384                                 }
385                                 dstPathOrig := filepath.Join(*incoming, dst)
386                                 dstPath := dstPathOrig
387                                 dstPathCtr := 0
388                                 for {
389                                         if _, err = os.Stat(dstPath); err != nil {
390                                                 if os.IsNotExist(err) {
391                                                         break
392                                                 }
393                                                 ctx.LogE("rx-stat", les, err, func(les LEs) string {
394                                                         return fmt.Sprintf(
395                                                                 "Tossing file %s/%s (%s): %s: stating: %s",
396                                                                 ctx.NodeName(job.PktEnc.Sender), pktName,
397                                                                 humanize.IBytes(uint64(pktSize)), dst, dstPath,
398                                                         )
399                                                 })
400                                                 isBad = true
401                                                 goto Closing
402                                         }
403                                         dstPath = dstPathOrig + "." + strconv.Itoa(dstPathCtr)
404                                         dstPathCtr++
405                                 }
406                                 if err = os.Rename(tmp.Name(), dstPath); err != nil {
407                                         ctx.LogE("rx-rename", les, err, func(les LEs) string {
408                                                 return fmt.Sprintf(
409                                                         "Tossing file %s/%s (%s): %s: renaming",
410                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
411                                                         humanize.IBytes(uint64(pktSize)), dst,
412                                                 )
413                                         })
414                                         isBad = true
415                                 }
416                                 if err = DirSync(*incoming); err != nil {
417                                         ctx.LogE("rx-dirsync", les, err, func(les LEs) string {
418                                                 return fmt.Sprintf(
419                                                         "Tossing file %s/%s (%s): %s: dirsyncing",
420                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
421                                                         humanize.IBytes(uint64(pktSize)), dst,
422                                                 )
423                                         })
424                                         isBad = true
425                                 }
426                                 les = les[:len(les)-1] // delete Tmp
427                         }
428                         ctx.LogI("rx", les, func(les LEs) string {
429                                 return fmt.Sprintf(
430                                         "Got file %s (%s) from %s",
431                                         dst, humanize.IBytes(uint64(pktSize)),
432                                         ctx.NodeName(job.PktEnc.Sender),
433                                 )
434                         })
435                         if !dryRun {
436                                 if doSeen {
437                                         if fd, err := os.Create(job.Path + SeenSuffix); err == nil {
438                                                 fd.Close() // #nosec G104
439                                         }
440                                 }
441                                 if err = os.Remove(job.Path); err != nil {
442                                         ctx.LogE("rx-remove", les, err, func(les LEs) string {
443                                                 return fmt.Sprintf(
444                                                         "Tossing file %s/%s (%s): %s: removing",
445                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
446                                                         humanize.IBytes(uint64(pktSize)), dst,
447                                                 )
448                                         })
449                                         isBad = true
450                                 } else if ctx.HdrUsage {
451                                         os.Remove(job.Path + HdrSuffix)
452                                 }
453                                 if len(sendmail) > 0 && ctx.NotifyFile != nil {
454                                         cmd := exec.Command(
455                                                 sendmail[0],
456                                                 append(sendmail[1:], ctx.NotifyFile.To)...,
457                                         )
458                                         cmd.Stdin = newNotification(ctx.NotifyFile, fmt.Sprintf(
459                                                 "File from %s: %s (%s)",
460                                                 ctx.Neigh[*job.PktEnc.Sender].Name,
461                                                 dst,
462                                                 humanize.IBytes(uint64(pktSize)),
463                                         ), nil)
464                                         if err = cmd.Run(); err != nil {
465                                                 ctx.LogE("rx-notify", les, err, func(les LEs) string {
466                                                         return fmt.Sprintf(
467                                                                 "Tossing file %s/%s (%s): %s: notifying",
468                                                                 ctx.NodeName(job.PktEnc.Sender), pktName,
469                                                                 humanize.IBytes(uint64(pktSize)), dst,
470                                                         )
471                                                 })
472                                         }
473                                 }
474                         }
475
476                 case PktTypeFreq:
477                         if noFreq {
478                                 goto Closing
479                         }
480                         src := string(pkt.Path[:int(pkt.PathLen)])
481                         les := append(les, LE{"Type", "freq"}, LE{"Src", src})
482                         if filepath.IsAbs(src) {
483                                 ctx.LogE(
484                                         "rx-non-rel", les, errors.New("non-relative source path"),
485                                         func(les LEs) string {
486                                                 return fmt.Sprintf(
487                                                         "Tossing freq %s/%s (%s): %s: notifying",
488                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
489                                                         humanize.IBytes(uint64(pktSize)), src,
490                                                 )
491                                         },
492                                 )
493                                 isBad = true
494                                 goto Closing
495                         }
496                         dstRaw, err := ioutil.ReadAll(pipeR)
497                         if err != nil {
498                                 ctx.LogE("rx-read", les, err, func(les LEs) string {
499                                         return fmt.Sprintf(
500                                                 "Tossing freq %s/%s (%s): %s: reading",
501                                                 ctx.NodeName(job.PktEnc.Sender), pktName,
502                                                 humanize.IBytes(uint64(pktSize)), src,
503                                         )
504                                 })
505                                 isBad = true
506                                 goto Closing
507                         }
508                         dst := string(dstRaw)
509                         les = append(les, LE{"Dst", dst})
510                         sender := ctx.Neigh[*job.PktEnc.Sender]
511                         freqPath := sender.FreqPath
512                         if freqPath == nil {
513                                 ctx.LogE(
514                                         "rx-no-freq", les, errors.New("freqing is not allowed"),
515                                         func(les LEs) string {
516                                                 return fmt.Sprintf(
517                                                         "Tossing freq %s/%s (%s): %s -> %s",
518                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
519                                                         humanize.IBytes(uint64(pktSize)), src, dst,
520                                                 )
521                                         },
522                                 )
523                                 isBad = true
524                                 goto Closing
525                         }
526                         if !dryRun {
527                                 err = ctx.TxFile(
528                                         sender,
529                                         pkt.Nice,
530                                         filepath.Join(*freqPath, src),
531                                         dst,
532                                         sender.FreqChunked,
533                                         sender.FreqMinSize,
534                                         sender.FreqMaxSize,
535                                 )
536                                 if err != nil {
537                                         ctx.LogE("rx-tx", les, err, func(les LEs) string {
538                                                 return fmt.Sprintf(
539                                                         "Tossing freq %s/%s (%s): %s -> %s: txing",
540                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
541                                                         humanize.IBytes(uint64(pktSize)), src, dst,
542                                                 )
543                                         })
544                                         isBad = true
545                                         goto Closing
546                                 }
547                         }
548                         ctx.LogI("rx", les, func(les LEs) string {
549                                 return fmt.Sprintf(
550                                         "Got file request %s to %s",
551                                         src, ctx.NodeName(job.PktEnc.Sender),
552                                 )
553                         })
554                         if !dryRun {
555                                 if doSeen {
556                                         if fd, err := os.Create(job.Path + SeenSuffix); err == nil {
557                                                 fd.Close() // #nosec G104
558                                         }
559                                 }
560                                 if err = os.Remove(job.Path); err != nil {
561                                         ctx.LogE("rx-remove", les, err, func(les LEs) string {
562                                                 return fmt.Sprintf(
563                                                         "Tossing freq %s/%s (%s): %s -> %s: removing",
564                                                         ctx.NodeName(job.PktEnc.Sender), pktName,
565                                                         humanize.IBytes(uint64(pktSize)), src, dst,
566                                                 )
567                                         })
568                                         isBad = true
569                                 } else if ctx.HdrUsage {
570                                         os.Remove(job.Path + HdrSuffix)
571                                 }
572                                 if len(sendmail) > 0 && ctx.NotifyFreq != nil {
573                                         cmd := exec.Command(
574                                                 sendmail[0],
575                                                 append(sendmail[1:], ctx.NotifyFreq.To)...,
576                                         )
577                                         cmd.Stdin = newNotification(ctx.NotifyFreq, fmt.Sprintf(
578                                                 "Freq from %s: %s", sender.Name, src,
579                                         ), nil)
580                                         if err = cmd.Run(); err != nil {
581                                                 ctx.LogE("rx-notify", les, err, func(les LEs) string {
582                                                         return fmt.Sprintf(
583                                                                 "Tossing freq %s/%s (%s): %s -> %s: notifying",
584                                                                 ctx.NodeName(job.PktEnc.Sender), pktName,
585                                                                 humanize.IBytes(uint64(pktSize)), src, dst,
586                                                         )
587                                                 })
588                                         }
589                                 }
590                         }
591
592                 case PktTypeTrns:
593                         if noTrns {
594                                 goto Closing
595                         }
596                         dst := new([blake2b.Size256]byte)
597                         copy(dst[:], pkt.Path[:int(pkt.PathLen)])
598                         nodeId := NodeId(*dst)
599                         node, known := ctx.Neigh[nodeId]
600                         les := append(les, LE{"Type", "trns"}, LE{"Dst", nodeId})
601                         logMsg := func(les LEs) string {
602                                 return fmt.Sprintf(
603                                         "Tossing trns %s/%s (%s): %s",
604                                         ctx.NodeName(job.PktEnc.Sender),
605                                         pktName,
606                                         humanize.IBytes(uint64(pktSize)),
607                                         nodeId.String(),
608                                 )
609                         }
610                         if !known {
611                                 ctx.LogE("rx-unknown", les, errors.New("unknown node"), logMsg)
612                                 isBad = true
613                                 goto Closing
614                         }
615                         ctx.LogD("rx-tx", les, logMsg)
616                         if !dryRun {
617                                 if err = ctx.TxTrns(node, job.PktEnc.Nice, pktSize, pipeR); err != nil {
618                                         ctx.LogE("rx", les, err, func(les LEs) string {
619                                                 return logMsg(les) + ": txing"
620                                         })
621                                         isBad = true
622                                         goto Closing
623                                 }
624                         }
625                         ctx.LogI("rx", les, func(les LEs) string {
626                                 return fmt.Sprintf(
627                                         "Got transitional packet from %s to %s (%s)",
628                                         ctx.NodeName(job.PktEnc.Sender),
629                                         ctx.NodeName(&nodeId),
630                                         humanize.IBytes(uint64(pktSize)),
631                                 )
632                         })
633                         if !dryRun {
634                                 if doSeen {
635                                         if fd, err := os.Create(job.Path + SeenSuffix); err == nil {
636                                                 fd.Close() // #nosec G104
637                                         }
638                                 }
639                                 if err = os.Remove(job.Path); err != nil {
640                                         ctx.LogE("rx", les, err, func(les LEs) string {
641                                                 return fmt.Sprintf(
642                                                         "Tossing trns %s/%s (%s): %s: removing",
643                                                         ctx.NodeName(job.PktEnc.Sender),
644                                                         pktName,
645                                                         humanize.IBytes(uint64(pktSize)),
646                                                         ctx.NodeName(&nodeId),
647                                                 )
648                                         })
649                                         isBad = true
650                                 } else if ctx.HdrUsage {
651                                         os.Remove(job.Path + HdrSuffix)
652                                 }
653                         }
654
655                 default:
656                         ctx.LogE(
657                                 "rx-type-unknown", les, errors.New("unknown type"),
658                                 func(les LEs) string {
659                                         return fmt.Sprintf(
660                                                 "Tossing %s/%s (%s)",
661                                                 ctx.NodeName(job.PktEnc.Sender),
662                                                 pktName,
663                                                 humanize.IBytes(uint64(pktSize)),
664                                         )
665                                 },
666                         )
667                         isBad = true
668                 }
669         Closing:
670                 pipeR.Close() // #nosec G104
671         }
672         return isBad
673 }
674
675 func (ctx *Ctx) AutoToss(
676         nodeId *NodeId,
677         nice uint8,
678         doSeen, noFile, noFreq, noExec, noTrns bool,
679 ) (chan struct{}, chan bool) {
680         finish := make(chan struct{})
681         badCode := make(chan bool)
682         go func() {
683                 bad := false
684                 for {
685                         select {
686                         case <-finish:
687                                 badCode <- bad
688                                 break
689                         default:
690                         }
691                         time.Sleep(time.Second)
692                         bad = !ctx.Toss(nodeId, nice, false, doSeen, noFile, noFreq, noExec, noTrns)
693                 }
694         }()
695         return finish, badCode
696 }