mirror of
https://github.com/go-i2p/go-i2p.git
synced 2025-06-07 18:24:25 -04:00
Add DatabaseLookup and test it
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
test-i2np-header-all: test-i2np-type test-i2np-message test-i2np-expiration test-i2np-ntcp-components test-i2np-data test-i2np-regression test-i2np-build-request-record test-i2np-build-response-record
|
test-i2np-header-all: test-i2np-type test-i2np-message test-i2np-expiration test-i2np-ntcp-components test-i2np-data test-i2np-regression test-i2np-build-request-record test-i2np-build-response-record test-i2np-database-lookup
|
||||||
|
|
||||||
test-i2np-type:
|
test-i2np-type:
|
||||||
$(GO) test -v ./lib/i2np -run TestReadI2NPTypeWith
|
$(GO) test -v ./lib/i2np -run TestReadI2NPTypeWith
|
||||||
@ -37,6 +37,31 @@ test-i2np-build-response-record:
|
|||||||
$(GO) test -v ./lib/i2np -run TestReadBuildResponseRecordTooLittleData
|
$(GO) test -v ./lib/i2np -run TestReadBuildResponseRecordTooLittleData
|
||||||
$(GO) test -v ./lib/i2np -run TestReadBuildResponseRecordValidData
|
$(GO) test -v ./lib/i2np -run TestReadBuildResponseRecordValidData
|
||||||
|
|
||||||
|
test-i2np-database-lookup:
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupKeyTooLittleData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupKeyValidData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupFromTooLittleData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupFromValidData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupFlagsTooLittleData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupFlagsValidData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupReplyTunnelIDTooLittleData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupReplyTunnelIDNotIncluded
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupReplyTunnelIDValidData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupSizeTooLittleData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupSizeValidData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupExcludedPeersTooLittleData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupExcludedPeersZeroSize
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupExcludedPeersValidData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupReplyKeyTooLittleData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupReplyKeyValidData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupTagsTooLittleData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupTagsValidData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupReplyTagsTooLittleData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupReplyTagsZeroTags
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupReplyTagsValidData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupTooLittleData
|
||||||
|
$(GO) test -v ./lib/i2np -run TestReadDatabaseLookupValidData
|
||||||
|
|
||||||
.PHONY: test-i2np-header-all \
|
.PHONY: test-i2np-header-all \
|
||||||
test-i2np-type \
|
test-i2np-type \
|
||||||
test-i2np-message \
|
test-i2np-message \
|
||||||
@ -45,4 +70,5 @@ test-i2np-build-response-record:
|
|||||||
test-i2np-data \
|
test-i2np-data \
|
||||||
test-i2np-regression \
|
test-i2np-regression \
|
||||||
test-i2np-build-request-record \
|
test-i2np-build-request-record \
|
||||||
test-i2np-build-response-record
|
test-i2np-build-response-record \
|
||||||
|
test-i2np-database-lookup
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package i2np
|
package i2np
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
common "github.com/go-i2p/go-i2p/lib/common/data"
|
common "github.com/go-i2p/go-i2p/lib/common/data"
|
||||||
"github.com/go-i2p/go-i2p/lib/common/session_key"
|
"github.com/go-i2p/go-i2p/lib/common/session_key"
|
||||||
"github.com/go-i2p/go-i2p/lib/common/session_tag"
|
"github.com/go-i2p/go-i2p/lib/common/session_tag"
|
||||||
@ -8,8 +12,8 @@ import (
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
I2P I2NP DatabaseLookup
|
I2P I2NP DatabaseLookup
|
||||||
https://geti2p.net/spec/i2np
|
https://geti2p.net/spec/i2np#databaselookup
|
||||||
Accurate for version 0.9.28
|
Accurate for version 0.9.65
|
||||||
|
|
||||||
+----+----+----+----+----+----+----+----+
|
+----+----+----+----+----+----+----+----+
|
||||||
| SHA256 hash as the key to look up |
|
| SHA256 hash as the key to look up |
|
||||||
@ -21,7 +25,7 @@ Accurate for version 0.9.28
|
|||||||
| |
|
| |
|
||||||
+----+----+----+----+----+----+----+----+
|
+----+----+----+----+----+----+----+----+
|
||||||
| SHA256 hash of the routerInfo |
|
| SHA256 hash of the routerInfo |
|
||||||
+ who is asking, or the gateway to +
|
+ who is asking or the gateway to +
|
||||||
| send the reply to |
|
| send the reply to |
|
||||||
+ +
|
+ +
|
||||||
| |
|
| |
|
||||||
@ -30,7 +34,7 @@ Accurate for version 0.9.28
|
|||||||
+----+----+----+----+----+----+----+----+
|
+----+----+----+----+----+----+----+----+
|
||||||
|flag| reply_tunnelId | size | |
|
|flag| reply_tunnelId | size | |
|
||||||
+----+----+----+----+----+----+----+ +
|
+----+----+----+----+----+----+----+ +
|
||||||
| SHA256 of $key1 to exclude |
|
| SHA256 of key1 to exclude |
|
||||||
+ +
|
+ +
|
||||||
| |
|
| |
|
||||||
+ +
|
+ +
|
||||||
@ -38,7 +42,7 @@ Accurate for version 0.9.28
|
|||||||
+ +----+
|
+ +----+
|
||||||
| | |
|
| | |
|
||||||
+----+----+----+----+----+----+----+ +
|
+----+----+----+----+----+----+----+ +
|
||||||
| SHA256 of $key2 to exclude |
|
| SHA256 of key2 to exclude |
|
||||||
+ +
|
+ +
|
||||||
~ ~
|
~ ~
|
||||||
+ +----+
|
+ +----+
|
||||||
@ -95,12 +99,20 @@ flags ::
|
|||||||
with version 0.9.16 or higher.
|
with version 0.9.16 or higher.
|
||||||
01 => LS lookup, return LeaseSet or
|
01 => LS lookup, return LeaseSet or
|
||||||
DatabaseSearchReplyMessage
|
DatabaseSearchReplyMessage
|
||||||
|
As of release 0.9.38, may also return a
|
||||||
|
LeaseSet2, MetaLeaseSet, or EncryptedLeaseSet.
|
||||||
10 => RI lookup, return RouterInfo or
|
10 => RI lookup, return RouterInfo or
|
||||||
DatabaseSearchReplyMessage
|
DatabaseSearchReplyMessage
|
||||||
11 => exploration lookup, return DatabaseSearchReplyMessage
|
11 => exploration lookup, return DatabaseSearchReplyMessage
|
||||||
containing non-floodfill routers only (replaces an
|
containing non-floodfill routers only (replaces an
|
||||||
excludedPeer of all zeroes)
|
excludedPeer of all zeroes)
|
||||||
bits 7-4:
|
bit 4: ECIESFlag
|
||||||
|
before release 0.9.46 ignored
|
||||||
|
as of release 0.9.46:
|
||||||
|
0 => send unencrypted or ElGamal reply
|
||||||
|
1 => send ChaCha/Poly encrypted reply using enclosed key
|
||||||
|
(whether tag is enclosed depends on bit 1)
|
||||||
|
bits 7-5:
|
||||||
through release 0.9.5, must be set to 0
|
through release 0.9.5, must be set to 0
|
||||||
as of release 0.9.6, ignored, set to 0 for compatibility with
|
as of release 0.9.6, ignored, set to 0 for compatibility with
|
||||||
future uses and with older routers
|
future uses and with older routers
|
||||||
@ -108,7 +120,7 @@ flags ::
|
|||||||
reply_tunnelId ::
|
reply_tunnelId ::
|
||||||
4 byte TunnelID
|
4 byte TunnelID
|
||||||
only included if deliveryFlag == 1
|
only included if deliveryFlag == 1
|
||||||
tunnelId of the tunnel to send the reply to
|
tunnelId of the tunnel to send the reply to, nonzero
|
||||||
|
|
||||||
size ::
|
size ::
|
||||||
2 byte Integer
|
2 byte Integer
|
||||||
@ -124,18 +136,53 @@ excludedPeers ::
|
|||||||
to list non-floodfill routers only.
|
to list non-floodfill routers only.
|
||||||
|
|
||||||
reply_key ::
|
reply_key ::
|
||||||
32 byte SessionKey
|
32 byte key
|
||||||
only included if encryptionFlag == 1, only as of release 0.9.7
|
see below
|
||||||
|
|
||||||
tags ::
|
tags ::
|
||||||
1 byte Integer
|
1 byte Integer
|
||||||
valid range: 1-32 (typically 1)
|
valid range: 1-32 (typically 1)
|
||||||
the number of reply tags that follow
|
the number of reply tags that follow
|
||||||
only included if encryptionFlag == 1, only as of release 0.9.7
|
see below
|
||||||
|
|
||||||
|
reply_tags ::
|
||||||
|
one or more 8 or 32 byte session tags (typically one)
|
||||||
|
see below
|
||||||
|
|
||||||
|
|
||||||
|
ElG to ElG
|
||||||
|
|
||||||
|
reply_key ::
|
||||||
|
32 byte SessionKey big-endian
|
||||||
|
only included if encryptionFlag == 1 AND ECIESFlag == 0, only as of release 0.9.7
|
||||||
|
|
||||||
|
tags ::
|
||||||
|
1 byte Integer
|
||||||
|
valid range: 1-32 (typically 1)
|
||||||
|
the number of reply tags that follow
|
||||||
|
only included if encryptionFlag == 1 AND ECIESFlag == 0, only as of release 0.9.7
|
||||||
|
|
||||||
reply_tags ::
|
reply_tags ::
|
||||||
one or more 32 byte SessionTags (typically one)
|
one or more 32 byte SessionTags (typically one)
|
||||||
only included if encryptionFlag == 1, only as of release 0.9.7
|
only included if encryptionFlag == 1 AND ECIESFlag == 0, only as of release 0.9.7
|
||||||
|
|
||||||
|
|
||||||
|
ECIES to ElG
|
||||||
|
|
||||||
|
reply_key ::
|
||||||
|
32 byte ECIES SessionKey big-endian
|
||||||
|
only included if encryptionFlag == 0 AND ECIESFlag == 1, only as of release 0.9.46
|
||||||
|
|
||||||
|
tags ::
|
||||||
|
1 byte Integer
|
||||||
|
required value: 1
|
||||||
|
the number of reply tags that follow
|
||||||
|
only included if encryptionFlag == 0 AND ECIESFlag == 1, only as of release 0.9.46
|
||||||
|
|
||||||
|
reply_tags ::
|
||||||
|
an 8 byte ECIES SessionTag
|
||||||
|
only included if encryptionFlag == 0 AND ECIESFlag == 1, only as of release 0.9.46
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type DatabaseLookup struct {
|
type DatabaseLookup struct {
|
||||||
@ -146,6 +193,209 @@ type DatabaseLookup struct {
|
|||||||
Size int
|
Size int
|
||||||
ExcludedPeers []common.Hash
|
ExcludedPeers []common.Hash
|
||||||
ReplyKey session_key.SessionKey
|
ReplyKey session_key.SessionKey
|
||||||
tags int
|
Tags int
|
||||||
ReplyTags []session_tag.SessionTag
|
ReplyTags []session_tag.SessionTag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA = errors.New("not enough i2np database lookup data")
|
||||||
|
|
||||||
|
func ReadDatabaseLookup(data []byte) (DatabaseLookup, error) {
|
||||||
|
log.Debug("Reading DatabaseLookup")
|
||||||
|
databaseLookup := DatabaseLookup{}
|
||||||
|
|
||||||
|
length, key, err := readDatabaseLookupKey(data)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Failed to read Key")
|
||||||
|
return databaseLookup, err
|
||||||
|
}
|
||||||
|
databaseLookup.Key = key
|
||||||
|
|
||||||
|
length, from, err := readDatabaseLookupFrom(length, data)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Failed to read From")
|
||||||
|
return databaseLookup, err
|
||||||
|
}
|
||||||
|
databaseLookup.From = from
|
||||||
|
|
||||||
|
length, flags, err := readDatabaseLookupFlags(length, data)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Failed to read Flags")
|
||||||
|
return databaseLookup, err
|
||||||
|
}
|
||||||
|
databaseLookup.Flags = flags
|
||||||
|
|
||||||
|
length, replyTunnelID, err := readDatabaseLookupReplyTunnelID(flags, length, data)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Failed to read ReplyTunnelID")
|
||||||
|
return databaseLookup, err
|
||||||
|
}
|
||||||
|
databaseLookup.ReplyTunnelID = replyTunnelID
|
||||||
|
|
||||||
|
length, size, err := readDatabaseLookupSize(length, data)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Failed to read Size")
|
||||||
|
return databaseLookup, err
|
||||||
|
}
|
||||||
|
databaseLookup.Size = size
|
||||||
|
|
||||||
|
length, excludedPeers, err := readDatabaseLookupExcludedPeers(length, data, size)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Failed to read ExcludedPeers")
|
||||||
|
return databaseLookup, err
|
||||||
|
}
|
||||||
|
databaseLookup.ExcludedPeers = excludedPeers
|
||||||
|
|
||||||
|
length, reply_key, err := readDatabaseLookupReplyKey(length, data)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Failed to read ReplyKey")
|
||||||
|
return databaseLookup, err
|
||||||
|
}
|
||||||
|
databaseLookup.ReplyKey = reply_key
|
||||||
|
|
||||||
|
length, tags, err := readDatabaseLookupTags(length, data)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Failed to read Tags")
|
||||||
|
return databaseLookup, err
|
||||||
|
}
|
||||||
|
databaseLookup.Tags = tags
|
||||||
|
|
||||||
|
length, reply_tags, err := readDatabaseLookupReplyTags(length, data, tags)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Failed to read ReplyTags")
|
||||||
|
return databaseLookup, err
|
||||||
|
}
|
||||||
|
databaseLookup.ReplyTags = reply_tags
|
||||||
|
|
||||||
|
log.Debug("DatabaseLookup read successfully")
|
||||||
|
return databaseLookup, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readDatabaseLookupKey(data []byte) (int, common.Hash, error) {
|
||||||
|
if len(data) < 32 {
|
||||||
|
return 0, common.Hash{}, ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA
|
||||||
|
}
|
||||||
|
|
||||||
|
key := common.Hash(data[:32])
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"at": "i2np.readDatabaseLookupKey",
|
||||||
|
"key": key,
|
||||||
|
}).Debug("parsed_database_lookup_key")
|
||||||
|
return 32, key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readDatabaseLookupFrom(length int, data []byte) (int, common.Hash, error) {
|
||||||
|
if len(data) < length + 32 {
|
||||||
|
return length, common.Hash{}, ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA
|
||||||
|
}
|
||||||
|
|
||||||
|
from := common.Hash(data[length:length + 32])
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"at": "i2np.database_lookup.readDatabaseLookupFrom",
|
||||||
|
"from": from,
|
||||||
|
}).Debug("parsed_database_lookup_from")
|
||||||
|
return length + 32, from, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readDatabaseLookupFlags(length int, data []byte) (int, byte, error) {
|
||||||
|
if len(data) < length + 1 {
|
||||||
|
return length, byte(0), ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA
|
||||||
|
}
|
||||||
|
flags := data[length]
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"at": "i2np.database_lookup.readDatabaseLookupFlags",
|
||||||
|
"flags": flags,
|
||||||
|
}).Debug("parsed_database_lookup_flags")
|
||||||
|
return length + 1, flags, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readDatabaseLookupReplyTunnelID(flags byte, length int, data []byte) (int, [4]byte, error) {
|
||||||
|
if flags & 1 != 1 {
|
||||||
|
return length, [4]byte{}, nil
|
||||||
|
}
|
||||||
|
if len(data) < length + 4 {
|
||||||
|
return length, [4]byte{}, ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA
|
||||||
|
}
|
||||||
|
|
||||||
|
replyTunnelID := [4]byte(data[length:length + 4])
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"at": "i2np.database_lookup.readDatabaseLookupReplyTunnelID",
|
||||||
|
"reply_tunnel_id": replyTunnelID,
|
||||||
|
}).Debug("parsed_database_lookup_reply_tunnel_id")
|
||||||
|
return length + 4, replyTunnelID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readDatabaseLookupSize(length int, data []byte) (int, int, error) {
|
||||||
|
if len(data) < length + 2 {
|
||||||
|
return length, 0, ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA
|
||||||
|
}
|
||||||
|
|
||||||
|
size := common.Integer(data[length:length + 2]).Int()
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"at": "i2np.database_lookup.readDatabaseLookupSize",
|
||||||
|
"size": size,
|
||||||
|
}).Debug("parsed_database_lookup_size")
|
||||||
|
return length + 2, size, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readDatabaseLookupExcludedPeers(length int, data []byte, size int) (int, []common.Hash, error) {
|
||||||
|
if len(data) < length + size * 32 {
|
||||||
|
return length, []common.Hash{}, ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA
|
||||||
|
}
|
||||||
|
var excludedPeers []common.Hash
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
offset := length + i * 32
|
||||||
|
peer := common.Hash(data[offset:offset + 32])
|
||||||
|
excludedPeers = append(excludedPeers, peer)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"at": "i2np.database_lookup.readDatabaseLookupExcludedPeers",
|
||||||
|
"excluded_peers": excludedPeers,
|
||||||
|
}).Debug("parsed_database_lookup_excluded_peers")
|
||||||
|
return length + size * 32, excludedPeers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readDatabaseLookupReplyKey(length int, data []byte) (int, session_key.SessionKey, error) {
|
||||||
|
if len(data) < length + 32 {
|
||||||
|
return length, session_key.SessionKey{}, ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA
|
||||||
|
}
|
||||||
|
replyKey := session_key.SessionKey(data[length:length + 32])
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"at": "i2np.database_lookup.readDatabaseLookupReplyKey",
|
||||||
|
"reply_key": replyKey,
|
||||||
|
}).Debug("parsed_database_lookup_reply_key")
|
||||||
|
return length + 32, replyKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readDatabaseLookupTags(length int, data []byte) (int, int, error) {
|
||||||
|
if len(data) < length + 1 {
|
||||||
|
return length, 0, ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA
|
||||||
|
}
|
||||||
|
tags := int(data[length])
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"at": "i2np.database_lookup.readDatabaseLookupTags",
|
||||||
|
"tags": tags,
|
||||||
|
}).Debug("parsed_database_lookup_tags")
|
||||||
|
return length + 1, tags, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readDatabaseLookupReplyTags(length int, data []byte, tags int) (int, []session_tag.SessionTag, error) {
|
||||||
|
if len(data) < length + tags * 32 {
|
||||||
|
return length, []session_tag.SessionTag{}, ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA
|
||||||
|
}
|
||||||
|
var reply_tags []session_tag.SessionTag
|
||||||
|
for i := 0; i < tags; i++ {
|
||||||
|
offset := length + i * 32
|
||||||
|
tag := session_tag.SessionTag(data[offset:offset + 32])
|
||||||
|
reply_tags = append(reply_tags, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"at": "i2np.database_lookup.readDatabaseLookupReplyTags",
|
||||||
|
"reply_tags": reply_tags,
|
||||||
|
}).Debug("parsed_database_lookup_reply_tags")
|
||||||
|
return length + tags * 32, reply_tags, nil
|
||||||
|
}
|
||||||
|
430
lib/i2np/database_lookup_test.go
Normal file
430
lib/i2np/database_lookup_test.go
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
package i2np
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
common "github.com/go-i2p/go-i2p/lib/common/data"
|
||||||
|
"github.com/go-i2p/go-i2p/lib/common/session_key"
|
||||||
|
"github.com/go-i2p/go-i2p/lib/common/session_tag"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupKeyTooLittleData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length, key, err := readDatabaseLookupKey([]byte{0x01})
|
||||||
|
assert.Equal(0, length)
|
||||||
|
assert.Equal(common.Hash{}, key)
|
||||||
|
assert.Equal(ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupKeyValidData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
data := make([]byte, 32)
|
||||||
|
for i := range 31 {
|
||||||
|
data[i] = 0x31
|
||||||
|
}
|
||||||
|
length, key, err := readDatabaseLookupKey(data)
|
||||||
|
expected := common.Hash(data)
|
||||||
|
|
||||||
|
assert.Equal(32, length)
|
||||||
|
assert.Equal(expected, key)
|
||||||
|
assert.Equal(nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupFromTooLittleData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 32
|
||||||
|
prev := make([]byte, length)
|
||||||
|
data := append(prev, 0x01)
|
||||||
|
|
||||||
|
length, key, err := readDatabaseLookupFrom(length, data)
|
||||||
|
assert.Equal(32, length)
|
||||||
|
assert.Equal(common.Hash{}, key)
|
||||||
|
assert.Equal(ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupFromValidData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 32
|
||||||
|
prev := make([]byte, length)
|
||||||
|
expectedFrom := make([]byte, 32)
|
||||||
|
expectedFrom[23] = 0x21
|
||||||
|
expectedFrom[29] = 0x37
|
||||||
|
data := append(prev, expectedFrom...)
|
||||||
|
length, from, err := readDatabaseLookupFrom(length, data)
|
||||||
|
expected := common.Hash(expectedFrom)
|
||||||
|
|
||||||
|
assert.Equal(64, length)
|
||||||
|
assert.Equal(from, expected)
|
||||||
|
assert.Equal(nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupFlagsTooLittleData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 64
|
||||||
|
prev := make([]byte, length)
|
||||||
|
data := prev
|
||||||
|
|
||||||
|
length, flags, err := readDatabaseLookupFlags(length, data)
|
||||||
|
assert.Equal(64, length)
|
||||||
|
assert.Equal(byte(0), flags)
|
||||||
|
assert.Equal(ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupFlagsValidData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 64
|
||||||
|
prev := make([]byte, length)
|
||||||
|
expected := byte(0x1)
|
||||||
|
data := append(prev, expected)
|
||||||
|
length, flags, err := readDatabaseLookupFlags(length, data)
|
||||||
|
|
||||||
|
assert.Equal(65, length)
|
||||||
|
assert.Equal(flags, expected)
|
||||||
|
assert.Equal(nil, err)
|
||||||
|
}
|
||||||
|
func TestReadDatabaseLookupReplyTunnelIDTooLittleData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 64
|
||||||
|
prev := make([]byte, length)
|
||||||
|
flag := byte(0x1)
|
||||||
|
data := append(prev, flag)
|
||||||
|
|
||||||
|
excessData := make([]byte, 2)
|
||||||
|
excessData[1] = 0x32
|
||||||
|
data = append(data, excessData...)
|
||||||
|
length, flags, err := readDatabaseLookupFlags(length, data)
|
||||||
|
|
||||||
|
length, replyTunnelID, err := readDatabaseLookupReplyTunnelID(flags, length, data)
|
||||||
|
assert.Equal(65, length)
|
||||||
|
assert.Equal([4]byte{}, replyTunnelID)
|
||||||
|
assert.Equal(ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupReplyTunnelIDNotIncluded(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 65
|
||||||
|
data := make([]byte, length)
|
||||||
|
length, flags, err := readDatabaseLookupFlags(length, data)
|
||||||
|
|
||||||
|
length, tunnelID, err := readDatabaseLookupReplyTunnelID(flags, length, data)
|
||||||
|
assert.Equal(65, length)
|
||||||
|
assert.Equal([4]byte{}, tunnelID)
|
||||||
|
assert.Equal(nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupReplyTunnelIDValidData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 64
|
||||||
|
prev := make([]byte, length)
|
||||||
|
flag := byte(0x1)
|
||||||
|
data := append(prev, flag)
|
||||||
|
|
||||||
|
expected := make([]byte, 4)
|
||||||
|
expected[1] = 0x32
|
||||||
|
expected[3] = 0x34
|
||||||
|
data = append(data, expected...)
|
||||||
|
length, flags, err := readDatabaseLookupFlags(length, data)
|
||||||
|
|
||||||
|
length, replyTunnelID, err := readDatabaseLookupReplyTunnelID(flags, length, data)
|
||||||
|
assert.Equal(69, length)
|
||||||
|
assert.Equal([4]byte(expected), replyTunnelID)
|
||||||
|
assert.Equal(nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupSizeTooLittleData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 65
|
||||||
|
data := make([]byte, length)
|
||||||
|
data = append(data, 0x2)
|
||||||
|
|
||||||
|
length, size, err := readDatabaseLookupSize(length, data)
|
||||||
|
assert.Equal(65, length)
|
||||||
|
assert.Equal(0, size)
|
||||||
|
assert.Equal(ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupSizeValidData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 65
|
||||||
|
data := make([]byte, length)
|
||||||
|
expectedSizeData := []byte{0x16,0x9}
|
||||||
|
data = append(data, expectedSizeData...)
|
||||||
|
|
||||||
|
length, size, err := readDatabaseLookupSize(length, data)
|
||||||
|
assert.Equal(67, length)
|
||||||
|
assert.Equal(common.Integer(expectedSizeData).Int(), size)
|
||||||
|
assert.Equal(nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupExcludedPeersTooLittleData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 65
|
||||||
|
data := make([]byte, length)
|
||||||
|
sizeData := []byte{0x0,0x3}
|
||||||
|
data = append(data, sizeData...)
|
||||||
|
data = append(data, 0x23)
|
||||||
|
|
||||||
|
length, size, err := readDatabaseLookupSize(length, data)
|
||||||
|
length, excludedPeers, err := readDatabaseLookupExcludedPeers(length, data, size)
|
||||||
|
assert.Equal([]common.Hash{}, excludedPeers)
|
||||||
|
assert.Equal(67, length)
|
||||||
|
assert.Equal(ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupExcludedPeersZeroSize(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 65
|
||||||
|
data := make([]byte, length)
|
||||||
|
sizeData := []byte{0x0,0x0}
|
||||||
|
data = append(data, sizeData...)
|
||||||
|
data = append(data, 0x23)
|
||||||
|
|
||||||
|
length, size, err := readDatabaseLookupSize(length, data)
|
||||||
|
|
||||||
|
var expectedExcludedPeers []common.Hash
|
||||||
|
|
||||||
|
length, excludedPeers, err := readDatabaseLookupExcludedPeers(length, data, size)
|
||||||
|
assert.Equal(expectedExcludedPeers, excludedPeers)
|
||||||
|
assert.Equal(67, length)
|
||||||
|
assert.Equal(nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupExcludedPeersValidData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 65
|
||||||
|
data := make([]byte, length)
|
||||||
|
sizeData := []byte{0x0,0x3}
|
||||||
|
data = append(data, sizeData...)
|
||||||
|
|
||||||
|
length, size, err := readDatabaseLookupSize(length, data)
|
||||||
|
|
||||||
|
var expectedExcludedPeers []common.Hash
|
||||||
|
for i := range size {
|
||||||
|
peer := make([]byte, 32)
|
||||||
|
// random data:
|
||||||
|
peer[i + 1] = 0x43
|
||||||
|
peer[i + 23] = 0x89
|
||||||
|
expectedExcludedPeers = append(expectedExcludedPeers, common.Hash(peer))
|
||||||
|
data = append(data, peer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
length, excludedPeers, err := readDatabaseLookupExcludedPeers(length, data, size)
|
||||||
|
assert.Equal(expectedExcludedPeers, excludedPeers)
|
||||||
|
assert.Equal(67 + 32 * size, length)
|
||||||
|
assert.Equal(nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupReplyKeyTooLittleData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 67
|
||||||
|
data := make([]byte, length)
|
||||||
|
data = append(data, 0x2)
|
||||||
|
|
||||||
|
length, replyKey, err := readDatabaseLookupReplyKey(length, data)
|
||||||
|
assert.Equal(67, length)
|
||||||
|
assert.Equal(session_key.SessionKey{}, replyKey)
|
||||||
|
assert.Equal(ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupReplyKeyValidData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 67
|
||||||
|
data := make([]byte, length)
|
||||||
|
expectedReplyKeyData := make([]byte, 32)
|
||||||
|
expectedReplyKeyData[3] = 0x31
|
||||||
|
expectedReplyKey := session_key.SessionKey(expectedReplyKeyData)
|
||||||
|
data = append(data, expectedReplyKeyData...)
|
||||||
|
|
||||||
|
length, replyKey, err := readDatabaseLookupReplyKey(length, data)
|
||||||
|
assert.Equal(67 + 32, length)
|
||||||
|
assert.Equal(expectedReplyKey, replyKey)
|
||||||
|
assert.Equal(nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupTagsTooLittleData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 99
|
||||||
|
data := make([]byte, length)
|
||||||
|
|
||||||
|
length, tags, err := readDatabaseLookupTags(length, data)
|
||||||
|
assert.Equal(99, length)
|
||||||
|
assert.Equal(0, tags)
|
||||||
|
assert.Equal(ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupTagsValidData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 99
|
||||||
|
data := make([]byte, length)
|
||||||
|
expected := 121
|
||||||
|
data = append(data, byte(expected))
|
||||||
|
|
||||||
|
length, tags, err := readDatabaseLookupTags(length, data)
|
||||||
|
assert.Equal(100, length)
|
||||||
|
assert.Equal(expected, tags)
|
||||||
|
assert.Equal(nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupReplyTagsTooLittleData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 99
|
||||||
|
data := make([]byte, length)
|
||||||
|
tags := 10
|
||||||
|
data = append(data, byte(tags))
|
||||||
|
data = append(data, 0x34)
|
||||||
|
|
||||||
|
length, tags, err := readDatabaseLookupTags(length, data)
|
||||||
|
length, replyTags, err := readDatabaseLookupReplyTags(length, data, tags)
|
||||||
|
assert.Equal(100, length)
|
||||||
|
assert.Equal([]session_tag.SessionTag{}, replyTags)
|
||||||
|
assert.Equal(ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupReplyTagsZeroTags(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 99
|
||||||
|
data := make([]byte, length)
|
||||||
|
tags := 0
|
||||||
|
data = append(data, byte(tags))
|
||||||
|
data = append(data, 0x23)
|
||||||
|
|
||||||
|
length, tags, err := readDatabaseLookupTags(length, data)
|
||||||
|
|
||||||
|
var expectedReplyTags []session_tag.SessionTag
|
||||||
|
|
||||||
|
length, replyTags, err := readDatabaseLookupReplyTags(length, data, tags)
|
||||||
|
assert.Equal(expectedReplyTags, replyTags)
|
||||||
|
assert.Equal(100, length)
|
||||||
|
assert.Equal(nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupReplyTagsValidData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 99
|
||||||
|
data := make([]byte, length)
|
||||||
|
tags := 10
|
||||||
|
data = append(data, byte(tags))
|
||||||
|
|
||||||
|
length, tags, err := readDatabaseLookupTags(length, data)
|
||||||
|
|
||||||
|
var expectedReplyTags []session_tag.SessionTag
|
||||||
|
for i := range tags {
|
||||||
|
tag := make([]byte, 32)
|
||||||
|
// random data:
|
||||||
|
tag[i + 1] = 0x43
|
||||||
|
tag[i + 5] = 0x89
|
||||||
|
expectedReplyTags = append(expectedReplyTags, session_tag.SessionTag(tag))
|
||||||
|
data = append(data, tag...)
|
||||||
|
}
|
||||||
|
|
||||||
|
length, replyTags, err := readDatabaseLookupReplyTags(length, data, tags)
|
||||||
|
assert.Equal(expectedReplyTags, replyTags)
|
||||||
|
assert.Equal(100 + 32 * tags, length)
|
||||||
|
assert.Equal(nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupTooLittleData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
length := 67
|
||||||
|
data := make([]byte, length)
|
||||||
|
expectedReplyKeyData := make([]byte, 32)
|
||||||
|
expectedReplyKeyData[3] = 0x31
|
||||||
|
expectedReplyKey := session_key.SessionKey(expectedReplyKeyData)
|
||||||
|
data = append(data, expectedReplyKeyData...)
|
||||||
|
|
||||||
|
databaseLookup, err := ReadDatabaseLookup(data)
|
||||||
|
assert.Equal(expectedReplyKey, databaseLookup.ReplyKey)
|
||||||
|
assert.Equal(ERR_DATABASE_LOOKUP_NOT_ENOUGH_DATA, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadDatabaseLookupValidData(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
data := make([]byte, 32)
|
||||||
|
for i := range 31 {
|
||||||
|
data[i] = 0x31
|
||||||
|
}
|
||||||
|
expectedKey := common.Hash(data)
|
||||||
|
|
||||||
|
from := make([]byte, 32)
|
||||||
|
from[14] = 0x69
|
||||||
|
from[27] = 0x15
|
||||||
|
data = append(data, from...)
|
||||||
|
expectedFrom := common.Hash(from)
|
||||||
|
|
||||||
|
expectedFlags := byte(0x1)
|
||||||
|
data = append(data, expectedFlags)
|
||||||
|
|
||||||
|
tunnelIDData := make([]byte, 4)
|
||||||
|
tunnelIDData[0] = 0xff
|
||||||
|
tunnelIDData[2] = 0xf2
|
||||||
|
data = append(data, tunnelIDData...)
|
||||||
|
expectedTunnelID := [4]byte(tunnelIDData)
|
||||||
|
|
||||||
|
sizeData := []byte{0x0,0xf}
|
||||||
|
data = append(data, sizeData...)
|
||||||
|
expectedSize := common.Integer(sizeData).Int()
|
||||||
|
|
||||||
|
var expectedExcludedPeers []common.Hash
|
||||||
|
for i := range expectedSize {
|
||||||
|
peer := make([]byte, 32)
|
||||||
|
// random data:
|
||||||
|
peer[i + 5] = 0xdd
|
||||||
|
peer[i + 13] = 0x35
|
||||||
|
expectedExcludedPeers = append(expectedExcludedPeers, common.Hash(peer))
|
||||||
|
data = append(data, peer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
replyKeyData := make([]byte, 32)
|
||||||
|
replyKeyData[6] = 0x11
|
||||||
|
replyKeyData[14] = 0x13
|
||||||
|
data = append(data, replyKeyData...)
|
||||||
|
expectedReplyKey := session_key.SessionKey(replyKeyData)
|
||||||
|
|
||||||
|
expectedTags := 15
|
||||||
|
data = append(data, byte(expectedTags))
|
||||||
|
|
||||||
|
var expectedReplyTags []session_tag.SessionTag
|
||||||
|
for i := range expectedTags {
|
||||||
|
tag := make([]byte, 32)
|
||||||
|
// random data:
|
||||||
|
tag[i + 3] = 0x22
|
||||||
|
tag[i + 13] = 0x11
|
||||||
|
expectedReplyTags = append(expectedReplyTags, session_tag.SessionTag(tag))
|
||||||
|
data = append(data, tag...)
|
||||||
|
}
|
||||||
|
databaseLookup, err := ReadDatabaseLookup(data)
|
||||||
|
assert.Equal(expectedKey, databaseLookup.Key)
|
||||||
|
assert.Equal(expectedFrom, databaseLookup.From)
|
||||||
|
assert.Equal(expectedFlags, databaseLookup.Flags)
|
||||||
|
assert.Equal(expectedTunnelID, databaseLookup.ReplyTunnelID)
|
||||||
|
assert.Equal(expectedSize, databaseLookup.Size)
|
||||||
|
assert.Equal(expectedExcludedPeers, databaseLookup.ExcludedPeers)
|
||||||
|
assert.Equal(expectedReplyKey, databaseLookup.ReplyKey)
|
||||||
|
assert.Equal(expectedTags, databaseLookup.Tags)
|
||||||
|
assert.Equal(expectedReplyTags, databaseLookup.ReplyTags)
|
||||||
|
assert.Equal(err, nil)
|
||||||
|
}
|
Reference in New Issue
Block a user