diff --git a/go.mod b/go.mod index 7951eebd21..65786eae13 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/AudriusButkevicius/pfilter v0.0.0-20190627213056-c55ef6137fc6 - github.com/SkycoinProject/dmsg v0.2.3-0.20200626071453-e2e73212a9ab + github.com/SkycoinProject/dmsg v0.2.3 github.com/SkycoinProject/skycoin v0.27.0 github.com/SkycoinProject/yamux v0.0.0-20191213015001-a36efeefbf6a github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect @@ -20,7 +20,6 @@ require ( github.com/mmcloughlin/avo v0.0.0-20200523190732-4439b6b2c061 // indirect github.com/pkg/profile v1.5.0 github.com/prometheus/client_golang v1.7.1 - github.com/prometheus/common v0.10.0 // indirect github.com/rakyll/statik v0.1.7 github.com/schollz/progressbar/v2 v2.15.0 github.com/shirou/gopsutil v2.20.5+incompatible diff --git a/go.sum b/go.sum index 3bd14d7290..56187ed1f7 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ github.com/AudriusButkevicius/pfilter v0.0.0-20190627213056-c55ef6137fc6 h1:Apvc github.com/AudriusButkevicius/pfilter v0.0.0-20190627213056-c55ef6137fc6/go.mod h1:1N0EEx/irz4B1qV17wW82TFbjQrE7oX316Cki6eDY0Q= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/SkycoinProject/dmsg v0.2.3-0.20200626071453-e2e73212a9ab h1:Tk6A+wHK/geAOZcwcvpKsVRtEGz91y2FM6Y6ePtt0/M= -github.com/SkycoinProject/dmsg v0.2.3-0.20200626071453-e2e73212a9ab/go.mod h1:qLrCsFiggHokPHyHH8069v6DawaD16SiUc8ml9W7CEo= +github.com/SkycoinProject/dmsg v0.2.3 h1:x6Wok/CXnAWdngMQ1q0sOiP81r9G21EeP4jnDfxEEJk= +github.com/SkycoinProject/dmsg v0.2.3/go.mod h1:qLrCsFiggHokPHyHH8069v6DawaD16SiUc8ml9W7CEo= github.com/SkycoinProject/skycoin v0.27.0 h1:N3IHxj8ossHOcsxLYOYugT+OaELLncYHJHxbbYLPPmY= github.com/SkycoinProject/skycoin v0.27.0/go.mod h1:xqPLOKh5B6GBZlGA7B5IJfQmCy7mwimD9NlqxR3gMXo= github.com/SkycoinProject/yamux v0.0.0-20191213015001-a36efeefbf6a h1:6nHCJqh7trsuRcpMC5JmtDukUndn2VC9sY64K6xQ7hQ= diff --git a/vendor/github.com/SkycoinProject/dmsg/.gitignore b/vendor/github.com/SkycoinProject/dmsg/.gitignore index 7084aa6b1c..553a6e7917 100644 --- a/vendor/github.com/SkycoinProject/dmsg/.gitignore +++ b/vendor/github.com/SkycoinProject/dmsg/.gitignore @@ -17,3 +17,5 @@ bin/ /dmsgpty-cli /dmsgpty-host /dmsgpty-ui + +/hello.txt diff --git a/vendor/github.com/SkycoinProject/dmsg/README.md b/vendor/github.com/SkycoinProject/dmsg/README.md index b83ba96dcc..764663601c 100644 --- a/vendor/github.com/SkycoinProject/dmsg/README.md +++ b/vendor/github.com/SkycoinProject/dmsg/README.md @@ -25,6 +25,10 @@ Legend: The connection between a `dmsg.Client` and `dmsg.Server` is called a `dmsg.Session`. A connection between two `dmsg.Client`s (via a `dmsg.Server`) is called a `dmsg.Stream`. A data unit of the dmsg network is called a `dmsg.Frame`. +## Dmsg tools and libraries + +- [`dmsgget`](./docs/dmsgget.md) - Simplified `wget` over `dmsg`. + ## Additional resources - [`dmsg` examples.](./examples) - [`dmsg.Discovery` documentation.](./cmd/dmsg-discovery/README.md) diff --git a/vendor/github.com/SkycoinProject/dmsg/disc/entry.go b/vendor/github.com/SkycoinProject/dmsg/disc/entry.go index a8679e02ed..821aa44f9d 100644 --- a/vendor/github.com/SkycoinProject/dmsg/disc/entry.go +++ b/vendor/github.com/SkycoinProject/dmsg/disc/entry.go @@ -10,7 +10,11 @@ import ( "github.com/SkycoinProject/dmsg/cipher" ) -const currentVersion = "0.0.1" +const ( + currentVersion = "0.0.1" + entryLifetime = 1 * time.Minute + allowedEntryTimestampError = 100 * time.Millisecond +) var ( // ErrKeyNotFound occurs in case when entry of public key is not found @@ -262,7 +266,11 @@ func (e *Entry) Validate() error { } now, ts := time.Now(), time.Unix(0, e.Timestamp) - if ts.After(now) || ts.Before(now.Add(-time.Minute)) { + earliestAcceptable := now.Add(-entryLifetime) + latestAcceptable := now.Add(allowedEntryTimestampError) // in case when time on nodes mismatches a bit + + if ts.After(latestAcceptable) || ts.Before(earliestAcceptable) { + log.Warnf("Entry timestamp %v is not correct (now: %v)", ts, now) return ErrValidationOutdatedTime } diff --git a/vendor/github.com/SkycoinProject/dmsg/entity_common.go b/vendor/github.com/SkycoinProject/dmsg/entity_common.go index 67df7ad671..b576d287fa 100644 --- a/vendor/github.com/SkycoinProject/dmsg/entity_common.go +++ b/vendor/github.com/SkycoinProject/dmsg/entity_common.go @@ -16,6 +16,9 @@ import ( // EntityCommon contains the common fields and methods for server and client entities. type EntityCommon struct { + // atomic requires 64-bit alignment for struct field access + lastUpdate int64 // Timestamp (in unix seconds) of last update. + pk cipher.PubKey sk cipher.SecKey dc disc.APIClient @@ -24,7 +27,6 @@ type EntityCommon struct { sessionsMx *sync.Mutex updateInterval time.Duration // Minimum duration between discovery entry updates. - lastUpdate int64 // Timestamp (in unix seconds) of last update. log logrus.FieldLogger @@ -175,7 +177,7 @@ func (c *EntityCommon) updateServerEntry(ctx context.Context, addr string, maxSe entry.Server.Address = addr log = log.WithField("addr", entry.Server.Address) } - log.Info("Updating discovery entry...") + log.Debug("Updating entry.") return c.dc.PutEntry(ctx, c.sk, entry) } @@ -244,7 +246,7 @@ func (c *EntityCommon) updateClientEntry(ctx context.Context, done chan struct{} } entry.Client.DelegatedServers = srvPKs - c.log.WithField("entry", entry).Info("Updating entry.") + c.log.WithField("entry", entry).Debug("Updating entry.") return c.dc.PutEntry(ctx, c.sk, entry) } diff --git a/vendor/github.com/SkycoinProject/dmsg/noise/noise.go b/vendor/github.com/SkycoinProject/dmsg/noise/noise.go index 54ad607a4f..3637f5f306 100644 --- a/vendor/github.com/SkycoinProject/dmsg/noise/noise.go +++ b/vendor/github.com/SkycoinProject/dmsg/noise/noise.go @@ -3,6 +3,7 @@ package noise import ( "crypto/rand" "encoding/binary" + "errors" "fmt" "github.com/SkycoinProject/skycoin/src/util/logging" @@ -13,6 +14,9 @@ import ( var noiseLogger = logging.MustGetLogger("noise") // TODO: initialize properly or remove +// ErrInvalidCipherText occurs when a ciphertext is received which is too short in size. +var ErrInvalidCipherText = errors.New("noise decrypt unsafe: ciphertext cannot be less than 8 bytes") + // nonceSize is the noise cipher state's nonce size in bytes. const nonceSize = 8 @@ -139,8 +143,7 @@ func (ns *Noise) EncryptUnsafe(plaintext []byte) []byte { // be used with external lock. func (ns *Noise) DecryptUnsafe(ciphertext []byte) ([]byte, error) { if len(ciphertext) < nonceSize { - //TODO(evanlinjin): Log the following: "noise decrypt unsafe: cipher text cannot be less than 8 bytes". - return make([]byte, 0), nil + return nil, ErrInvalidCipherText } recvSeq := binary.BigEndian.Uint64(ciphertext[:nonceSize]) if recvSeq <= ns.decNonce { @@ -156,8 +159,7 @@ type NonceMap map[uint64]struct{} // DecryptWithNonceMap is equivalent to DecryptNonce, instead it uses NonceMap to track nonces instead of a counter. func (ns *Noise) DecryptWithNonceMap(nm NonceMap, ciphertext []byte) ([]byte, error) { if len(ciphertext) < nonceSize { - //TODO(evanlinjin): Log the following: "noise decrypt unsafe: cipher text cannot be less than 8 bytes". - return make([]byte, 0), nil + return nil, ErrInvalidCipherText } recvSeq := binary.BigEndian.Uint64(ciphertext[:nonceSize]) if _, ok := nm[recvSeq]; ok { diff --git a/vendor/github.com/SkycoinProject/dmsg/noise/read_writer.go b/vendor/github.com/SkycoinProject/dmsg/noise/read_writer.go index cd861390f0..2d76ea59b1 100644 --- a/vendor/github.com/SkycoinProject/dmsg/noise/read_writer.go +++ b/vendor/github.com/SkycoinProject/dmsg/noise/read_writer.go @@ -6,6 +6,7 @@ import ( "encoding/binary" "fmt" "io" + "net" "sync" "time" @@ -32,11 +33,15 @@ func (timeoutError) Error() string { return "deadline exceeded" } func (timeoutError) Timeout() bool { return true } func (timeoutError) Temporary() bool { return true } -type netError struct{ Err error } +type netError struct { + err error + timeout bool + temp bool +} -func (e *netError) Error() string { return e.Err.Error() } -func (netError) Timeout() bool { return false } -func (netError) Temporary() bool { return true } +func (e *netError) Error() string { return e.err.Error() } +func (e *netError) Timeout() bool { return e.timeout } +func (e *netError) Temporary() bool { return e.temp } // ReadWriter implements noise encrypted read writer. type ReadWriter struct { @@ -45,9 +50,11 @@ type ReadWriter struct { rawInput *bufio.Reader input bytes.Buffer - rMx sync.Mutex - wPad bytes.Reader + rErr error + rMx sync.Mutex + + wErr error wMx sync.Mutex } @@ -68,35 +75,63 @@ func (rw *ReadWriter) Read(p []byte) (int, error) { return rw.input.Read(p) } - ciphertext, err := ReadRawFrame(rw.rawInput) - if err != nil { - return 0, err + if rw.rErr != nil { + return 0, rw.rErr } - plaintext, err := rw.ns.DecryptUnsafe(ciphertext) - if err != nil { - // TODO(evanlinjin): log error here. - return 0, nil + + for { + ciphertext, err := ReadRawFrame(rw.rawInput) + if err != nil { + return 0, rw.processReadError(err) + } + + plaintext, err := rw.ns.DecryptUnsafe(ciphertext) + if err != nil { + return 0, rw.processReadError(err) + } + + if len(plaintext) == 0 { + continue + } + + return ioutil.BufRead(&rw.input, plaintext, p) + } +} + +// processReadError processes error before returning. +// * Ensure error implements net.Error +// * If error is non-temporary, save error in state so further reads will fail. +func (rw *ReadWriter) processReadError(err error) error { + if nErr, ok := err.(net.Error); ok { + if !nErr.Temporary() { + rw.rErr = err + } + return err } - if len(plaintext) == 0 { - return 0, nil + + err = &netError{ + err: err, + timeout: false, + temp: false, } - return ioutil.BufRead(&rw.input, plaintext, p) + rw.rErr = err + return err } func (rw *ReadWriter) Write(p []byte) (n int, err error) { rw.wMx.Lock() defer rw.wMx.Unlock() + if rw.wErr != nil { + return 0, rw.wErr + } + // Check for timeout errors. if _, err = rw.origin.Write(nil); err != nil { return 0, err } - for rw.wPad.Len() > 0 { - if _, err = rw.wPad.WriteTo(rw.origin); err != nil { - return 0, err - } - } + p = p[:] for len(p) > 0 { // Enforce max frame size. @@ -105,11 +140,24 @@ func (rw *ReadWriter) Write(p []byte) (n int, err error) { wn = maxPayloadSize } - writtenB, err := WriteRawFrame(rw.origin, rw.ns.EncryptUnsafe(p[:wn])) - if !IsCompleteFrame(writtenB) { - rw.wPad.Reset(FillIncompleteFrame(writtenB)) - } + wb, err := WriteRawFrame(rw.origin, rw.ns.EncryptUnsafe(p[:wn])) if err != nil { + // when a short write occurs, it is hard to recover from so we + // consider it a permanent error + if len(wb) != 0 { + err = &netError{ + err: fmt.Errorf("%v: %w", io.ErrShortWrite, err), + timeout: false, + temp: false, + } + } + + // if error is permanent, we record it in the internal state so no + // further writes occurs + if !isTemp(err) { + rw.wErr = err + } + return n, err } @@ -225,7 +273,9 @@ func ReadRawFrame(r *bufio.Reader) (p []byte, err error) { prefix := int(binary.BigEndian.Uint16(prefixB)) if prefix > maxPrefixValue { return nil, &netError{ - Err: fmt.Errorf("noise prefix value %dB exceeds maximum %dB", prefix, maxPrefixValue), + err: fmt.Errorf("noise prefix value %dB exceeds maximum %dB", prefix, maxPrefixValue), + timeout: false, + temp: false, } } @@ -237,25 +287,13 @@ func ReadRawFrame(r *bufio.Reader) (p []byte, err error) { if _, err := r.Discard(prefixSize + prefix); err != nil { panic(fmt.Errorf("unexpected error when discarding %d bytes: %v", prefixSize+prefix, err)) } - return b[prefixSize:], nil -} -// IsCompleteFrame determines if a frame is fully formed. -func IsCompleteFrame(b []byte) bool { - if len(b) < prefixSize || len(b[prefixSize:]) != int(binary.BigEndian.Uint16(b)) { - return false - } - return true + return b[prefixSize:], nil } -// FillIncompleteFrame takes in an incomplete frame, and returns empty bytes to fill the incomplete frame. -func FillIncompleteFrame(b []byte) []byte { - originalLen := len(b) - b2 := b - - for len(b2) < prefixSize { - b2 = append(b2, byte(0)) +func isTemp(err error) bool { + if netErr, ok := err.(net.Error); ok && netErr.Temporary() { + return true } - b2 = append(b2, make([]byte, binary.BigEndian.Uint16(b2))...) - return b2[originalLen:] + return false } diff --git a/vendor/modules.txt b/vendor/modules.txt index 28e9d40eb0..de3a862666 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,7 +1,7 @@ # github.com/AudriusButkevicius/pfilter v0.0.0-20190627213056-c55ef6137fc6 ## explicit github.com/AudriusButkevicius/pfilter -# github.com/SkycoinProject/dmsg v0.2.3-0.20200626071453-e2e73212a9ab +# github.com/SkycoinProject/dmsg v0.2.3 ## explicit github.com/SkycoinProject/dmsg github.com/SkycoinProject/dmsg/buildinfo @@ -15,6 +15,7 @@ github.com/SkycoinProject/dmsg/httputil github.com/SkycoinProject/dmsg/ioutil github.com/SkycoinProject/dmsg/netutil github.com/SkycoinProject/dmsg/noise +github.com/SkycoinProject/dmsg/promutil github.com/SkycoinProject/dmsg/servermetrics # github.com/SkycoinProject/skycoin v0.27.0 ## explicit @@ -151,7 +152,6 @@ github.com/prometheus/client_golang/prometheus/promhttp # github.com/prometheus/client_model v0.2.0 github.com/prometheus/client_model/go # github.com/prometheus/common v0.10.0 -## explicit github.com/prometheus/common/expfmt github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg github.com/prometheus/common/model