]> Cypherpunks.ru repositories - nncp.git/blob - src/cypherpunks.ru/nncp/toss_test.go
Replace Twofish/HKDF with ChaCha20/BLAKE2X for speed and simplicity
[nncp.git] / src / cypherpunks.ru / nncp / toss_test.go
1 /*
2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2017 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, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package nncp
20
21 import (
22         "bytes"
23         "crypto/rand"
24         "fmt"
25         "io"
26         "io/ioutil"
27         "os"
28         "path/filepath"
29         "strconv"
30         "testing"
31         "testing/quick"
32
33         "github.com/davecgh/go-xdr/xdr2"
34         "golang.org/x/crypto/blake2b"
35 )
36
37 var (
38         TDebug bool = false
39 )
40
41 func dirFiles(path string) []string {
42         dir, err := os.Open(path)
43         if err != nil {
44                 panic(err)
45         }
46         defer dir.Close()
47         names, err := dir.Readdirnames(0)
48         if err != nil {
49                 panic(err)
50         }
51         return names
52 }
53
54 func TestTossEmail(t *testing.T) {
55         f := func(recipients [16]uint8) bool {
56                 for i, recipient := range recipients {
57                         recipients[i] = recipient % 8
58                 }
59                 spool, err := ioutil.TempDir("", "testtoss")
60                 if err != nil {
61                         panic(err)
62                 }
63                 defer os.RemoveAll(spool)
64                 nodeOur, err := NewNodeGenerate()
65                 if err != nil {
66                         t.Error(err)
67                         return false
68                 }
69                 ctx := Ctx{
70                         Spool:   spool,
71                         Self:    nodeOur,
72                         SelfId:  nodeOur.Id,
73                         Neigh:   make(map[NodeId]*Node),
74                         Alias:   make(map[string]*NodeId),
75                         LogPath: filepath.Join(spool, "log.log"),
76                         Debug:   TDebug,
77                 }
78                 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
79                 privates := make(map[uint8]*NodeOur)
80                 for _, recipient := range recipients {
81                         if _, exists := privates[recipient]; exists {
82                                 continue
83                         }
84                         our, err := NewNodeGenerate()
85                         if err != nil {
86                                 t.Error(err)
87                                 return false
88                         }
89                         privates[recipient] = our
90                         ctx.Neigh[*our.Id] = our.Their()
91                 }
92                 for _, recipient := range recipients {
93                         if err := ctx.TxMail(
94                                 ctx.Neigh[*privates[recipient].Id],
95                                 DefaultNiceMail,
96                                 "recipient",
97                                 []byte{123},
98                                 1<<15,
99                         ); err != nil {
100                                 t.Error(err)
101                                 return false
102                         }
103                 }
104                 for _, recipient := range recipients {
105                         ctx.Self = privates[recipient]
106                         rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
107                         os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
108                         if len(dirFiles(rxPath)) == 0 {
109                                 continue
110                         }
111                         ctx.Toss(ctx.Self.Id, DefaultNiceMail-1, false, false)
112                         if len(dirFiles(rxPath)) == 0 {
113                                 return false
114                         }
115                         ctx.Neigh[*nodeOur.Id].Sendmail = []string{"/bin/sh", "-c", "false"}
116                         ctx.Toss(ctx.Self.Id, DefaultNiceMail, false, false)
117                         if len(dirFiles(rxPath)) == 0 {
118                                 return false
119                         }
120                         ctx.Neigh[*nodeOur.Id].Sendmail = []string{
121                                 "/bin/sh", "-c",
122                                 fmt.Sprintf("cat >> %s", filepath.Join(spool, "mbox")),
123                         }
124                         ctx.Toss(ctx.Self.Id, DefaultNiceMail, false, false)
125                         if len(dirFiles(rxPath)) != 0 {
126                                 return false
127                         }
128                 }
129                 mbox, err := ioutil.ReadFile(filepath.Join(spool, "mbox"))
130                 if err != nil {
131                         return false
132                 }
133                 expected := make([]byte, 0, 16)
134                 for i := 0; i < 16; i++ {
135                         expected = append(expected, 123)
136                 }
137                 return bytes.Compare(mbox, expected) == 0
138         }
139         if err := quick.Check(f, nil); err != nil {
140                 t.Error(err)
141         }
142 }
143
144 func TestTossFile(t *testing.T) {
145         f := func(fileSizes []uint8) bool {
146                 if len(fileSizes) == 0 {
147                         return true
148                 }
149                 files := make(map[string][]byte)
150                 for i, fileSize := range fileSizes {
151                         data := make([]byte, fileSize)
152                         if _, err := io.ReadFull(rand.Reader, data); err != nil {
153                                 panic(err)
154                         }
155                         files[strconv.Itoa(i)] = data
156                 }
157                 spool, err := ioutil.TempDir("", "testtoss")
158                 if err != nil {
159                         panic(err)
160                 }
161                 defer os.RemoveAll(spool)
162                 nodeOur, err := NewNodeGenerate()
163                 if err != nil {
164                         t.Error(err)
165                         return false
166                 }
167                 ctx := Ctx{
168                         Spool:   spool,
169                         Self:    nodeOur,
170                         SelfId:  nodeOur.Id,
171                         Neigh:   make(map[NodeId]*Node),
172                         Alias:   make(map[string]*NodeId),
173                         LogPath: filepath.Join(spool, "log.log"),
174                         Debug:   TDebug,
175                 }
176                 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
177                 incomingPath := filepath.Join(spool, "incoming")
178                 for _, fileData := range files {
179                         checksum := blake2b.Sum256(fileData)
180                         fileName := ToBase32(checksum[:])
181                         src := filepath.Join(spool, fileName)
182                         if err := ioutil.WriteFile(src, fileData, os.FileMode(0600)); err != nil {
183                                 panic(err)
184                         }
185                         if err := ctx.TxFile(
186                                 ctx.Neigh[*nodeOur.Id],
187                                 DefaultNiceFile,
188                                 src,
189                                 fileName,
190                                 1<<15,
191                         ); err != nil {
192                                 t.Error(err)
193                                 return false
194                         }
195                 }
196                 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
197                 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
198                 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false)
199                 if len(dirFiles(rxPath)) == 0 {
200                         return false
201                 }
202                 ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
203                 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false)
204                 if len(dirFiles(rxPath)) != 0 {
205                         return false
206                 }
207                 for _, fileData := range files {
208                         checksum := blake2b.Sum256(fileData)
209                         fileName := ToBase32(checksum[:])
210                         data, err := ioutil.ReadFile(filepath.Join(incomingPath, fileName))
211                         if err != nil {
212                                 panic(err)
213                         }
214                         if bytes.Compare(data, fileData) != 0 {
215                                 return false
216                         }
217                 }
218                 return true
219         }
220         if err := quick.Check(f, nil); err != nil {
221                 t.Error(err)
222         }
223 }
224
225 func TestTossFileSameName(t *testing.T) {
226         f := func(filesRaw uint8) bool {
227                 files := int(filesRaw)%8 + 1
228                 spool, err := ioutil.TempDir("", "testtoss")
229                 if err != nil {
230                         panic(err)
231                 }
232                 defer os.RemoveAll(spool)
233                 nodeOur, err := NewNodeGenerate()
234                 if err != nil {
235                         t.Error(err)
236                         return false
237                 }
238                 ctx := Ctx{
239                         Spool:   spool,
240                         Self:    nodeOur,
241                         SelfId:  nodeOur.Id,
242                         Neigh:   make(map[NodeId]*Node),
243                         Alias:   make(map[string]*NodeId),
244                         LogPath: filepath.Join(spool, "log.log"),
245                         Debug:   TDebug,
246                 }
247                 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
248                 srcPath := filepath.Join(spool, "junk")
249                 if err = ioutil.WriteFile(
250                         srcPath,
251                         []byte("doesnotmatter"),
252                         os.FileMode(0600),
253                 ); err != nil {
254                         t.Error(err)
255                         return false
256                 }
257                 incomingPath := filepath.Join(spool, "incoming")
258                 for i := 0; i < files; i++ {
259                         if err := ctx.TxFile(
260                                 ctx.Neigh[*nodeOur.Id],
261                                 DefaultNiceFile,
262                                 srcPath,
263                                 "samefile",
264                                 1<<15,
265                         ); err != nil {
266                                 t.Error(err)
267                                 return false
268                         }
269                 }
270                 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
271                 os.Rename(filepath.Join(spool, ctx.Self.Id.String(), string(TTx)), rxPath)
272                 ctx.Neigh[*nodeOur.Id].Incoming = &incomingPath
273                 ctx.Toss(ctx.Self.Id, DefaultNiceFile, false, false)
274                 expected := make(map[string]struct{})
275                 expected["samefile"] = struct{}{}
276                 for i := 0; i < files-1; i++ {
277                         expected["samefile"+strconv.Itoa(i)] = struct{}{}
278                 }
279                 for _, filename := range dirFiles(incomingPath) {
280                         if _, exists := expected[filename]; !exists {
281                                 return false
282                         }
283                         delete(expected, filename)
284                 }
285                 if len(expected) != 0 {
286                         return false
287                 }
288                 return true
289         }
290         if err := quick.Check(f, nil); err != nil {
291                 t.Error(err)
292         }
293 }
294
295 func TestTossFreq(t *testing.T) {
296         f := func(fileSizes []uint8) bool {
297                 if len(fileSizes) == 0 {
298                         return true
299                 }
300                 spool, err := ioutil.TempDir("", "testtoss")
301                 if err != nil {
302                         panic(err)
303                 }
304                 defer os.RemoveAll(spool)
305                 nodeOur, err := NewNodeGenerate()
306                 if err != nil {
307                         t.Error(err)
308                         return false
309                 }
310                 ctx := Ctx{
311                         Spool:   spool,
312                         Self:    nodeOur,
313                         SelfId:  nodeOur.Id,
314                         Neigh:   make(map[NodeId]*Node),
315                         Alias:   make(map[string]*NodeId),
316                         LogPath: filepath.Join(spool, "log.log"),
317                         Debug:   TDebug,
318                 }
319                 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
320                 files := make(map[string][]byte)
321                 for i, fileSize := range fileSizes {
322                         fileData := make([]byte, fileSize)
323                         if _, err := io.ReadFull(rand.Reader, fileData); err != nil {
324                                 panic(err)
325                         }
326                         fileName := strconv.Itoa(i)
327                         files[fileName] = fileData
328                         if err := ctx.TxFreq(
329                                 ctx.Neigh[*nodeOur.Id],
330                                 DefaultNiceFreq,
331                                 fileName,
332                                 fileName,
333                                 1<<15,
334                         ); err != nil {
335                                 t.Error(err)
336                                 return false
337                         }
338                 }
339                 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
340                 txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
341                 os.Rename(txPath, rxPath)
342                 os.MkdirAll(txPath, os.FileMode(0700))
343                 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false)
344                 if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
345                         return false
346                 }
347                 ctx.Neigh[*nodeOur.Id].Freq = &spool
348                 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false)
349                 if len(dirFiles(txPath)) != 0 || len(dirFiles(rxPath)) == 0 {
350                         return false
351                 }
352                 for fileName, fileData := range files {
353                         if err := ioutil.WriteFile(
354                                 filepath.Join(spool, fileName),
355                                 fileData,
356                                 os.FileMode(0600),
357                         ); err != nil {
358                                 panic(err)
359                         }
360                 }
361                 ctx.Toss(ctx.Self.Id, DefaultNiceFreq, false, false)
362                 if len(dirFiles(txPath)) == 0 || len(dirFiles(rxPath)) != 0 {
363                         return false
364                 }
365                 for job := range ctx.Jobs(ctx.Self.Id, TTx) {
366                         var buf bytes.Buffer
367                         _, _, err := PktEncRead(ctx.Self, ctx.Neigh, job.Fd, &buf)
368                         if err != nil {
369                                 t.Error(err)
370                                 return false
371                         }
372                         var pkt Pkt
373                         if _, err = xdr.Unmarshal(&buf, &pkt); err != nil {
374                                 t.Error(err)
375                                 return false
376                         }
377                         dst := string(pkt.Path[:int(pkt.PathLen)])
378                         if bytes.Compare(buf.Bytes(), files[dst]) != 0 {
379                                 return false
380                         }
381                 }
382                 return true
383         }
384         if err := quick.Check(f, nil); err != nil {
385                 t.Error(err)
386         }
387 }
388
389 func TestTossTrns(t *testing.T) {
390         f := func(datumLens []uint8) bool {
391                 if len(datumLens) == 0 {
392                         return true
393                 }
394                 datum := make(map[int][]byte)
395                 for i, datumLen := range datumLens {
396                         datumLen += 64
397                         data := make([]byte, datumLen)
398                         if _, err := io.ReadFull(rand.Reader, data); err != nil {
399                                 panic(err)
400                         }
401                         datum[i] = data
402                 }
403                 spool, err := ioutil.TempDir("", "testtoss")
404                 if err != nil {
405                         panic(err)
406                 }
407                 defer os.RemoveAll(spool)
408                 nodeOur, err := NewNodeGenerate()
409                 if err != nil {
410                         t.Error(err)
411                         return false
412                 }
413                 ctx := Ctx{
414                         Spool:   spool,
415                         Self:    nodeOur,
416                         SelfId:  nodeOur.Id,
417                         Neigh:   make(map[NodeId]*Node),
418                         Alias:   make(map[string]*NodeId),
419                         LogPath: filepath.Join(spool, "log.log"),
420                         Debug:   TDebug,
421                 }
422                 ctx.Neigh[*nodeOur.Id] = nodeOur.Their()
423                 rxPath := filepath.Join(spool, ctx.Self.Id.String(), string(TRx))
424                 os.MkdirAll(rxPath, os.FileMode(0700))
425                 txPath := filepath.Join(spool, ctx.Self.Id.String(), string(TTx))
426                 os.MkdirAll(txPath, os.FileMode(0700))
427                 for _, data := range datum {
428                         pktTrans := Pkt{
429                                 Magic:   MagicNNCPPv1,
430                                 Type:    PktTypeTrns,
431                                 PathLen: blake2b.Size256,
432                                 Path:    new([MaxPathSize]byte),
433                         }
434                         copy(pktTrans.Path[:], nodeOur.Id[:])
435                         var dst bytes.Buffer
436                         if err := PktEncWrite(
437                                 ctx.Self,
438                                 ctx.Neigh[*nodeOur.Id],
439                                 &pktTrans,
440                                 123,
441                                 int64(len(data)),
442                                 0,
443                                 bytes.NewReader(data),
444                                 &dst,
445                         ); err != nil {
446                                 t.Error(err)
447                                 return false
448                         }
449                         checksum := blake2b.Sum256(dst.Bytes())
450                         if err := ioutil.WriteFile(
451                                 filepath.Join(rxPath, ToBase32(checksum[:])),
452                                 dst.Bytes(),
453                                 os.FileMode(0600),
454                         ); err != nil {
455                                 panic(err)
456                         }
457                 }
458                 ctx.Toss(ctx.Self.Id, 123, false, false)
459                 if len(dirFiles(rxPath)) != 0 {
460                         return false
461                 }
462                 for _, filename := range dirFiles(txPath) {
463                         dataRead, err := ioutil.ReadFile(filepath.Join(txPath, filename))
464                         if err != nil {
465                                 panic(err)
466                         }
467                         for k, data := range datum {
468                                 if bytes.Compare(dataRead, data) == 0 {
469                                         delete(datum, k)
470                                         break
471                                 }
472                         }
473                 }
474                 if len(datum) > 0 {
475                         return false
476                 }
477                 return true
478         }
479         if err := quick.Check(f, nil); err != nil {
480                 t.Error(err)
481         }
482 }