2017-07-02 15:53:10 -07:00
|
|
|
package i2np
|
|
|
|
|
|
|
|
import (
|
2022-07-11 23:41:58 -04:00
|
|
|
"time"
|
|
|
|
|
2025-02-26 19:22:48 -05:00
|
|
|
"github.com/samber/oops"
|
2024-10-22 17:37:17 -04:00
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
|
2022-07-11 23:41:58 -04:00
|
|
|
common "github.com/go-i2p/go-i2p/lib/common/data"
|
|
|
|
"github.com/go-i2p/go-i2p/lib/common/session_key"
|
2021-04-19 20:43:37 -04:00
|
|
|
"github.com/go-i2p/go-i2p/lib/tunnel"
|
2024-11-21 17:16:48 -05:00
|
|
|
"github.com/go-i2p/logger"
|
2017-07-02 15:53:10 -07:00
|
|
|
)
|
|
|
|
|
2024-10-23 00:06:06 -04:00
|
|
|
var log = logger.GetGoI2PLogger()
|
2024-10-18 22:41:40 -04:00
|
|
|
|
2017-07-02 15:53:10 -07:00
|
|
|
/*
|
|
|
|
I2P I2NP BuildRequestRecord
|
|
|
|
https://geti2p.net/spec/i2np
|
|
|
|
Accurate for version 0.9.28
|
|
|
|
|
|
|
|
ElGamal and AES encrypted:
|
|
|
|
|
|
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
| encrypted data... |
|
|
|
|
~ ~
|
|
|
|
| |
|
|
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
|
|
|
|
encrypted_data :: ElGamal and AES encrypted data
|
|
|
|
length -> 528
|
|
|
|
|
|
|
|
total length: 528
|
|
|
|
|
|
|
|
ElGamal encrypted:
|
|
|
|
|
|
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
| toPeer |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
| encrypted data... |
|
|
|
|
~ ~
|
|
|
|
| |
|
|
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
|
|
|
|
toPeer :: First 16 bytes of the SHA-256 Hash of the peer's RouterIdentity
|
|
|
|
length -> 16 bytes
|
|
|
|
|
|
|
|
encrypted_data :: ElGamal-2048 encrypted data (see notes)
|
|
|
|
length -> 512
|
|
|
|
|
|
|
|
total length: 528
|
|
|
|
|
|
|
|
Cleartext:
|
|
|
|
|
|
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
| receive_tunnel | our_ident |
|
|
|
|
+----+----+----+----+ +
|
|
|
|
| |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+ +----+----+----+----+
|
|
|
|
| | next_tunnel |
|
|
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
| next_ident |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
| layer_key |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
| iv_key |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
| reply_key |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
| reply_iv |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
|flag| request_time | send_msg_id
|
|
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
| |
|
|
|
|
+----+ +
|
|
|
|
| 29 bytes padding |
|
|
|
|
+ +
|
|
|
|
| |
|
|
|
|
+ +----+----+
|
|
|
|
| |
|
|
|
|
+----+----+----+----+----+----+
|
|
|
|
|
|
|
|
receive_tunnel :: TunnelId
|
|
|
|
length -> 4 bytes
|
|
|
|
|
|
|
|
our_ident :: Hash
|
|
|
|
length -> 32 bytes
|
|
|
|
|
|
|
|
next_tunnel :: TunnelId
|
|
|
|
length -> 4 bytes
|
|
|
|
|
|
|
|
next_ident :: Hash
|
|
|
|
length -> 32 bytes
|
|
|
|
|
|
|
|
layer_key :: SessionKey
|
|
|
|
length -> 32 bytes
|
|
|
|
|
|
|
|
iv_key :: SessionKey
|
|
|
|
length -> 32 bytes
|
|
|
|
|
|
|
|
reply_key :: SessionKey
|
|
|
|
length -> 32 bytes
|
|
|
|
|
|
|
|
reply_iv :: data
|
|
|
|
length -> 16 bytes
|
|
|
|
|
|
|
|
flag :: Integer
|
|
|
|
length -> 1 byte
|
|
|
|
|
|
|
|
request_time :: Integer
|
|
|
|
length -> 4 bytes
|
|
|
|
Hours since the epoch, i.e. current time / 3600
|
|
|
|
|
|
|
|
send_message_id :: Integer
|
|
|
|
length -> 4 bytes
|
|
|
|
|
|
|
|
padding :: Data
|
|
|
|
length -> 29 bytes
|
|
|
|
source -> random
|
|
|
|
|
|
|
|
total length: 222
|
|
|
|
*/
|
|
|
|
|
2024-10-03 21:52:49 -04:00
|
|
|
type (
|
|
|
|
BuildRequestRecordElGamalAES [528]byte
|
|
|
|
BuildRequestRecordElGamal [528]byte
|
|
|
|
)
|
2017-07-02 15:53:10 -07:00
|
|
|
|
|
|
|
type BuildRequestRecord struct {
|
|
|
|
ReceiveTunnel tunnel.TunnelID
|
|
|
|
OurIdent common.Hash
|
|
|
|
NextTunnel tunnel.TunnelID
|
|
|
|
NextIdent common.Hash
|
2022-07-11 23:41:58 -04:00
|
|
|
LayerKey session_key.SessionKey
|
|
|
|
IVKey session_key.SessionKey
|
|
|
|
ReplyKey session_key.SessionKey
|
2017-07-02 15:53:10 -07:00
|
|
|
ReplyIV [16]byte
|
2017-07-07 17:45:35 -07:00
|
|
|
Flag int
|
|
|
|
RequestTime time.Time
|
2017-07-02 15:53:10 -07:00
|
|
|
SendMessageID int
|
|
|
|
Padding [29]byte
|
|
|
|
}
|
2017-07-07 17:45:35 -07:00
|
|
|
|
2025-02-26 19:22:48 -05:00
|
|
|
var ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA = oops.Errorf("not enough i2np build request record data")
|
2017-07-07 17:45:35 -07:00
|
|
|
|
|
|
|
func ReadBuildRequestRecord(data []byte) (BuildRequestRecord, error) {
|
2024-10-18 22:41:40 -04:00
|
|
|
log.Debug("Reading BuildRequestRecord")
|
2017-07-07 17:45:35 -07:00
|
|
|
build_request_record := BuildRequestRecord{}
|
|
|
|
|
|
|
|
receive_tunnel, err := readBuildRequestRecordReceiveTunnel(data)
|
|
|
|
if err != nil {
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithError(err).Error("Failed to read ReceiveTunnel")
|
2017-07-07 17:45:35 -07:00
|
|
|
return build_request_record, err
|
|
|
|
}
|
|
|
|
build_request_record.ReceiveTunnel = receive_tunnel
|
|
|
|
|
|
|
|
our_ident, err := readBuildRequestRecordOurIdent(data)
|
|
|
|
if err != nil {
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithError(err).Error("Failed to read OurIdent")
|
2017-07-07 17:45:35 -07:00
|
|
|
return build_request_record, err
|
|
|
|
}
|
|
|
|
build_request_record.OurIdent = our_ident
|
|
|
|
|
|
|
|
next_tunnel, err := readBuildRequestRecordNextTunnel(data)
|
|
|
|
if err != nil {
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithError(err).Error("Failed to read NextTunnel")
|
2017-07-07 17:45:35 -07:00
|
|
|
return build_request_record, err
|
|
|
|
}
|
|
|
|
build_request_record.NextTunnel = next_tunnel
|
|
|
|
|
|
|
|
next_ident, err := readBuildRequestRecordNextIdent(data)
|
|
|
|
if err != nil {
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithError(err).Error("Failed to read NextIdent")
|
2017-07-07 17:45:35 -07:00
|
|
|
return build_request_record, err
|
|
|
|
}
|
|
|
|
build_request_record.NextIdent = next_ident
|
|
|
|
|
|
|
|
layer_key, err := readBuildRequestRecordLayerKey(data)
|
|
|
|
if err != nil {
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithError(err).Error("Failed to read LayerKey")
|
2017-07-07 17:45:35 -07:00
|
|
|
return build_request_record, err
|
|
|
|
}
|
|
|
|
build_request_record.LayerKey = layer_key
|
|
|
|
|
|
|
|
iv_key, err := readBuildRequestRecordIVKey(data)
|
|
|
|
if err != nil {
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithError(err).Error("Failed to read IVKey")
|
2017-07-07 17:45:35 -07:00
|
|
|
return build_request_record, err
|
|
|
|
}
|
|
|
|
build_request_record.IVKey = iv_key
|
|
|
|
|
|
|
|
reply_key, err := readBuildRequestRecordReplyKey(data)
|
|
|
|
if err != nil {
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithError(err).Error("Failed to read ReplyKey")
|
2017-07-07 17:45:35 -07:00
|
|
|
return build_request_record, err
|
|
|
|
}
|
|
|
|
build_request_record.ReplyKey = reply_key
|
|
|
|
|
|
|
|
reply_iv, err := readBuildRequestRecordReplyIV(data)
|
|
|
|
if err != nil {
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithError(err).Error("Failed to read ReplyIV")
|
2017-07-07 17:45:35 -07:00
|
|
|
return build_request_record, err
|
|
|
|
}
|
|
|
|
build_request_record.ReplyIV = reply_iv
|
|
|
|
|
|
|
|
flag, err := readBuildRequestRecordFlag(data)
|
|
|
|
if err != nil {
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithError(err).Error("Failed to read Flag")
|
2017-07-07 17:45:35 -07:00
|
|
|
return build_request_record, err
|
|
|
|
}
|
|
|
|
build_request_record.Flag = flag
|
|
|
|
|
|
|
|
request_time, err := readBuildRequestRecordRequestTime(data)
|
|
|
|
if err != nil {
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithError(err).Error("Failed to read RequestTime")
|
2017-07-07 17:45:35 -07:00
|
|
|
return build_request_record, err
|
|
|
|
}
|
|
|
|
build_request_record.RequestTime = request_time
|
|
|
|
|
2017-07-08 20:02:16 -07:00
|
|
|
send_message_id, err := readBuildRequestRecordSendMessageID(data)
|
2017-07-07 17:45:35 -07:00
|
|
|
if err != nil {
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithError(err).Error("Failed to read SendMessageID")
|
2017-07-07 17:45:35 -07:00
|
|
|
return build_request_record, err
|
|
|
|
}
|
|
|
|
build_request_record.SendMessageID = send_message_id
|
|
|
|
|
|
|
|
padding, err := readBuildRequestRecordPadding(data)
|
|
|
|
if err != nil {
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithError(err).Error("Failed to read Padding")
|
2017-07-07 17:45:35 -07:00
|
|
|
return build_request_record, err
|
|
|
|
}
|
|
|
|
build_request_record.Padding = padding
|
|
|
|
|
2024-10-18 22:41:40 -04:00
|
|
|
log.Debug("BuildRequestRecord read successfully")
|
2017-07-07 17:45:35 -07:00
|
|
|
return build_request_record, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func readBuildRequestRecordReceiveTunnel(data []byte) (tunnel.TunnelID, error) {
|
|
|
|
if len(data) < 4 {
|
|
|
|
return 0, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
|
|
|
|
}
|
|
|
|
|
|
|
|
receive_tunnel := tunnel.TunnelID(
|
2022-07-11 23:41:58 -04:00
|
|
|
common.Integer(data[0:4]).Int(),
|
2017-07-07 17:45:35 -07:00
|
|
|
)
|
|
|
|
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
2017-07-07 17:45:35 -07:00
|
|
|
"at": "i2np.readBuildRequestRecordReceiveTunnel",
|
|
|
|
"receieve_tunnel": receive_tunnel,
|
|
|
|
}).Debug("parsed_build_request_record_receive_tunnel")
|
|
|
|
return receive_tunnel, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func readBuildRequestRecordOurIdent(data []byte) (common.Hash, error) {
|
|
|
|
if len(data) < 36 {
|
|
|
|
return common.Hash{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
|
|
|
|
}
|
|
|
|
|
|
|
|
hash := common.Hash{}
|
|
|
|
copy(hash[:], data[4:36])
|
|
|
|
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
2017-07-07 17:45:35 -07:00
|
|
|
"at": "i2np.readBuildRequestRecordOurIdent",
|
|
|
|
}).Debug("parsed_build_request_record_our_ident")
|
|
|
|
return hash, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func readBuildRequestRecordNextTunnel(data []byte) (tunnel.TunnelID, error) {
|
|
|
|
if len(data) < 40 {
|
|
|
|
return 0, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
|
|
|
|
}
|
|
|
|
|
|
|
|
next_tunnel := tunnel.TunnelID(
|
2022-07-11 23:41:58 -04:00
|
|
|
common.Integer(data[36:40]).Int(),
|
2017-07-07 17:45:35 -07:00
|
|
|
)
|
|
|
|
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
2017-07-07 17:45:35 -07:00
|
|
|
"at": "i2np.readBuildRequestRecordNextTunnel",
|
|
|
|
"next_tunnel": next_tunnel,
|
|
|
|
}).Debug("parsed_build_request_record_next_tunnel")
|
|
|
|
return next_tunnel, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func readBuildRequestRecordNextIdent(data []byte) (common.Hash, error) {
|
|
|
|
if len(data) < 72 {
|
|
|
|
return common.Hash{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
|
|
|
|
}
|
|
|
|
|
|
|
|
hash := common.Hash{}
|
|
|
|
copy(hash[:], data[40:72])
|
|
|
|
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
2017-07-07 17:45:35 -07:00
|
|
|
"at": "i2np.readBuildRequestRecordNextIdent",
|
|
|
|
}).Debug("parsed_build_request_record_next_ident")
|
|
|
|
return hash, nil
|
|
|
|
}
|
|
|
|
|
2022-07-11 23:41:58 -04:00
|
|
|
func readBuildRequestRecordLayerKey(data []byte) (session_key.SessionKey, error) {
|
2017-07-07 17:45:35 -07:00
|
|
|
if len(data) < 104 {
|
2022-07-11 23:41:58 -04:00
|
|
|
return session_key.SessionKey{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
|
2017-07-07 17:45:35 -07:00
|
|
|
}
|
|
|
|
|
2022-07-11 23:41:58 -04:00
|
|
|
session_key := session_key.SessionKey{}
|
2017-07-07 17:45:35 -07:00
|
|
|
copy(session_key[:], data[72:104])
|
|
|
|
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
2017-07-07 17:45:35 -07:00
|
|
|
"at": "i2np.readBuildRequestRecordLayerKey",
|
|
|
|
}).Debug("parsed_build_request_record_layer_key")
|
|
|
|
return session_key, nil
|
|
|
|
}
|
|
|
|
|
2022-07-11 23:41:58 -04:00
|
|
|
func readBuildRequestRecordIVKey(data []byte) (session_key.SessionKey, error) {
|
2017-07-07 17:45:35 -07:00
|
|
|
if len(data) < 136 {
|
2022-07-11 23:41:58 -04:00
|
|
|
return session_key.SessionKey{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
|
2017-07-07 17:45:35 -07:00
|
|
|
}
|
|
|
|
|
2022-07-11 23:41:58 -04:00
|
|
|
session_key := session_key.SessionKey{}
|
2017-07-07 17:45:35 -07:00
|
|
|
copy(session_key[:], data[104:136])
|
|
|
|
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
2017-07-07 17:45:35 -07:00
|
|
|
"at": "i2np.readBuildRequestRecordIVKey",
|
|
|
|
}).Debug("parsed_build_request_record_iv_key")
|
|
|
|
return session_key, nil
|
|
|
|
}
|
|
|
|
|
2022-07-11 23:41:58 -04:00
|
|
|
func readBuildRequestRecordReplyKey(data []byte) (session_key.SessionKey, error) {
|
2017-07-07 17:45:35 -07:00
|
|
|
if len(data) < 168 {
|
2022-07-11 23:41:58 -04:00
|
|
|
return session_key.SessionKey{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
|
2017-07-07 17:45:35 -07:00
|
|
|
}
|
|
|
|
|
2022-07-11 23:41:58 -04:00
|
|
|
session_key := session_key.SessionKey{}
|
2017-07-07 17:45:35 -07:00
|
|
|
copy(session_key[:], data[136:168])
|
|
|
|
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
2017-07-07 17:45:35 -07:00
|
|
|
"at": "i2np.readBuildRequestRecordReplyKey",
|
|
|
|
}).Debug("parsed_build_request_record_reply_key")
|
|
|
|
return session_key, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func readBuildRequestRecordReplyIV(data []byte) ([16]byte, error) {
|
|
|
|
if len(data) < 184 {
|
|
|
|
return [16]byte{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
|
|
|
|
}
|
|
|
|
|
|
|
|
iv := [16]byte{}
|
|
|
|
copy(iv[:], data[168:184])
|
|
|
|
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
2017-07-07 17:45:35 -07:00
|
|
|
"at": "i2np.readBuildRequestRecordReplyIV",
|
|
|
|
}).Debug("parsed_build_request_record_reply_iv")
|
|
|
|
return iv, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func readBuildRequestRecordFlag(data []byte) (int, error) {
|
|
|
|
if len(data) < 185 {
|
|
|
|
return 0, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
|
|
|
|
}
|
|
|
|
|
2022-07-11 23:41:58 -04:00
|
|
|
flag := common.Integer([]byte{data[185]}).Int()
|
2017-07-07 17:45:35 -07:00
|
|
|
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
2017-07-07 17:45:35 -07:00
|
|
|
"at": "i2np.readBuildRequestRecordFlag",
|
|
|
|
"flag": flag,
|
|
|
|
}).Debug("parsed_build_request_record_flag")
|
|
|
|
return flag, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func readBuildRequestRecordRequestTime(data []byte) (time.Time, error) {
|
|
|
|
if len(data) < 189 {
|
|
|
|
return time.Time{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
|
|
|
|
}
|
|
|
|
|
2022-07-11 23:41:58 -04:00
|
|
|
count := common.Integer(data[185:189]).Int()
|
2017-07-07 17:45:35 -07:00
|
|
|
rtime := time.Unix(0, 0).Add(time.Duration(count) * time.Hour)
|
|
|
|
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
2017-07-07 17:45:35 -07:00
|
|
|
"at": "i2np.readBuildRequestRecordRequestTime",
|
|
|
|
}).Debug("parsed_build_request_record_request_time")
|
|
|
|
return rtime, nil
|
|
|
|
}
|
|
|
|
|
2017-07-08 20:02:16 -07:00
|
|
|
func readBuildRequestRecordSendMessageID(data []byte) (int, error) {
|
2017-07-07 17:45:35 -07:00
|
|
|
if len(data) < 193 {
|
|
|
|
return 0, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
|
|
|
|
}
|
|
|
|
|
2022-07-11 23:41:58 -04:00
|
|
|
send_message_id := common.Integer(data[189:193]).Int()
|
2017-07-07 17:45:35 -07:00
|
|
|
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
2017-07-07 17:45:35 -07:00
|
|
|
"at": "i2np.readBuildRequestRecordSendMessageID",
|
|
|
|
}).Debug("parsed_build_request_record_send_message_id")
|
|
|
|
return send_message_id, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func readBuildRequestRecordPadding(data []byte) ([29]byte, error) {
|
|
|
|
if len(data) < 222 {
|
|
|
|
return [29]byte{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
|
|
|
|
}
|
|
|
|
|
|
|
|
padding := [29]byte{}
|
|
|
|
copy(padding[:], data[193:222])
|
|
|
|
|
2024-10-18 22:41:40 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
2017-07-07 17:45:35 -07:00
|
|
|
"at": "i2np.readBuildRequestRecordPadding",
|
|
|
|
}).Debug("parsed_build_request_record_padding")
|
|
|
|
return padding, nil
|
|
|
|
}
|