From 9591f496ebef10a598df48ec1bd7177c72c786f2 Mon Sep 17 00:00:00 2001 From: satk0 Date: Wed, 18 Dec 2024 13:17:42 +0100 Subject: [PATCH] Add BuildResponseRecord --- doc/tests/header.mk | 22 ++++- lib/i2np/build_request_record.go | 2 +- lib/i2np/build_request_record_test.go | 2 +- lib/i2np/build_response_record.go | 93 ++++++++++++++++++-- lib/i2np/build_response_record_test.go | 117 +++++++++++++++++++++++++ 5 files changed, 227 insertions(+), 9 deletions(-) create mode 100644 lib/i2np/build_response_record_test.go diff --git a/doc/tests/header.mk b/doc/tests/header.mk index e18b30a..c17793c 100644 --- a/doc/tests/header.mk +++ b/doc/tests/header.mk @@ -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-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-type: $(GO) test -v ./lib/i2np -run TestReadI2NPTypeWith @@ -21,10 +21,28 @@ test-i2np-data: test-i2np-regression: $(GO) test -v ./lib/i2np -run TestCrasherRegression123781 +test-i2np-build-request-record: + $(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordReceiveTunnelTooLittleData + $(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordReceiveTunnelValidData + $(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordOurIdentTooLittleData + $(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordOurIdentValidData + +test-i2np-build-response-record: + $(GO) test -v ./lib/i2np -run TestReadBuildResponseRecordHashTooLittleData + $(GO) test -v ./lib/i2np -run TestReadBuildResponseRecordHashValidData + $(GO) test -v ./lib/i2np -run TestReadBuildResponseRecordRandomDataTooLittleData + $(GO) test -v ./lib/i2np -run TestReadBuildResponseRecordRandomDataValidData + $(GO) test -v ./lib/i2np -run TestReadBuildResponseRecordReplyTooLittleData + $(GO) test -v ./lib/i2np -run TestReadBuildResponseRecordReplyValidData + $(GO) test -v ./lib/i2np -run TestReadBuildResponseRecordTooLittleData + $(GO) test -v ./lib/i2np -run TestReadBuildResponseRecordValidData + .PHONY: test-i2np-header-all \ test-i2np-type \ test-i2np-message \ test-i2np-expiration \ test-i2np-ntcp-components \ test-i2np-data \ - test-i2np-regression \ No newline at end of file + test-i2np-regression \ + test-i2np-build-request-record \ + test-i2np-build-response-record diff --git a/lib/i2np/build_request_record.go b/lib/i2np/build_request_record.go index 45255f8..b9c7e2c 100644 --- a/lib/i2np/build_request_record.go +++ b/lib/i2np/build_request_record.go @@ -278,7 +278,7 @@ func readBuildRequestRecordReceiveTunnel(data []byte) (tunnel.TunnelID, error) { log.WithFields(logrus.Fields{ "at": "i2np.readBuildRequestRecordReceiveTunnel", - "receieve_tunnel": receive_tunnel, + "receive_tunnel": receive_tunnel, }).Debug("parsed_build_request_record_receive_tunnel") return receive_tunnel, nil } diff --git a/lib/i2np/build_request_record_test.go b/lib/i2np/build_request_record_test.go index 451c0a4..c9999fe 100644 --- a/lib/i2np/build_request_record_test.go +++ b/lib/i2np/build_request_record_test.go @@ -24,7 +24,7 @@ func TestReadBuildRequestRecordReceiveTunnelValidData(t *testing.T) { assert.Equal(nil, err) } -func TestReadBuildRequestRecordOurIdentTooLittleValidData(t *testing.T) { +func TestReadBuildRequestRecordOurIdentTooLittleData(t *testing.T) { assert := assert.New(t) receive_tunnel := []byte{0x00, 0x00, 0x00, 0x01} diff --git a/lib/i2np/build_response_record.go b/lib/i2np/build_response_record.go index b405521..6989cd4 100644 --- a/lib/i2np/build_response_record.go +++ b/lib/i2np/build_response_record.go @@ -1,13 +1,17 @@ package i2np import ( + "errors" + + "github.com/sirupsen/logrus" + common "github.com/go-i2p/go-i2p/lib/common/data" ) /* I2P I2NP BuildResponseRecord -https://geti2p.net/spec/i2np -Accurate for version 0.9.28 +https://geti2p.net/spec/i2np#buildresponserecord +Accurate for version 0.9.65 Encrypted: @@ -43,8 +47,87 @@ type ( BuildResponseRecordELGamal [528]byte ) +/* +BuildResponseRecord struct contains a response to BuildRequestRecord +concerning the creation of one hop in the tunnel +*/ type BuildResponseRecord struct { - Hash common.Hash - Padding [495]byte - Reply byte + Hash common.Hash + RandomData [495]byte + Reply byte } + +var ERR_BUILD_RESPONSE_RECORD_NOT_ENOUGH_DATA = errors.New("not enough i2np build request record data") + +func ReadBuildResponseRecord(data []byte) (BuildResponseRecord, error) { + log.Debug("Reading BuildResponseRecord") + build_response_record := BuildResponseRecord{} + + hash, err := readBuildResponseRecordHash(data) + if err != nil { + log.WithError(err).Error("Failed to read Hash") + return build_response_record, err + } + build_response_record.Hash = hash + + random_data, err := readBuildResponseRecordRandomData(data) + if err != nil { + log.WithError(err).Error("Failed to read Random Data") + return build_response_record, err + } + build_response_record.RandomData = random_data + + reply, err := readBuildResponseRecordReply(data) + if err != nil { + log.WithError(err).Error("Failed to read Reply") + return build_response_record, err + } + build_response_record.Reply = reply + + log.Debug("BuildResponseRecord read successfully") + return build_response_record, nil +} + +func readBuildResponseRecordHash(data []byte) (common.Hash, error) { + if len(data) < 32 { + return common.Hash{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA + } + + hash := common.Hash(data[0:32]) + + log.WithFields(logrus.Fields{ + "at": "i2np.readBuildResponseRecordHash", + "hash": hash, + }).Debug("parsed_build_response_record_hash") + return hash, nil +} + +func readBuildResponseRecordRandomData(data []byte) ([495]byte, error) { + if len(data) < 527 { + return [495]byte{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA + } + + random_data := [495]byte{} + copy(random_data[:], data[32:527]) + + log.WithFields(logrus.Fields{ + "at": "i2np.readBuildResponseRandomData", + "random_data": random_data, + }).Debug("parsed_build_response_record_random_data") + return random_data, nil +} + +func readBuildResponseRecordReply(data []byte) (byte, error) { + if len(data) < 528 { + return byte(0), ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA + } + + reply := data[527] + + log.WithFields(logrus.Fields{ + "at": "i2np.readBuildResponseReply", + "reply": reply, + }).Debug("parsed_build_response_record_reply") + return reply, nil +} + diff --git a/lib/i2np/build_response_record_test.go b/lib/i2np/build_response_record_test.go new file mode 100644 index 0000000..2249ab6 --- /dev/null +++ b/lib/i2np/build_response_record_test.go @@ -0,0 +1,117 @@ +package i2np + +import ( + "testing" + + common "github.com/go-i2p/go-i2p/lib/common/data" + "github.com/stretchr/testify/assert" +) + +func TestReadBuildResponseRecordHashTooLittleData(t *testing.T) { + assert := assert.New(t) + + hash, err := readBuildResponseRecordHash([]byte{0x01}) + assert.Equal(common.Hash{}, hash) + assert.Equal(ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA, err) +} + +func TestReadBuildResponseRecordHashValidData(t *testing.T) { + assert := assert.New(t) + + data := make([]byte, 32) + data[31] = 0x31 + res_hash, err := readBuildResponseRecordHash(data) + hash := common.Hash(data) + + assert.Equal(res_hash, hash) + assert.Equal(nil, err) +} + +func TestReadBuildResponseRecordRandomDataTooLittleData(t *testing.T) { + assert := assert.New(t) + + hash := make([]byte, 32) + data := append(hash, 0x01) + random_data, err := readBuildResponseRecordRandomData(data) + assert.Equal([495]byte{}, random_data) + assert.Equal(ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA, err) +} + +func TestReadBuildResponseRecordRandomDataValidData(t *testing.T) { + assert := assert.New(t) + + hash := make([]byte, 32) + hash[31] = 0x13 + random_data := make([]byte, 495) + random_data[493] = 0x33 + random_data[494] = 0x74 + data := append(hash, random_data...) + res_random_data, err := readBuildResponseRecordRandomData(data) + assert.Equal([495]byte(random_data), res_random_data) + assert.Equal(nil, err) +} + +func TestReadBuildResponseRecordReplyTooLittleData(t *testing.T) { + assert := assert.New(t) + + hash := make([]byte, 32) + random_data := make([]byte, 495) + random_data[493] = 0x33 + random_data[494] = 0x74 + data := append(hash, random_data...) + + res_reply, err := readBuildResponseRecordReply(data) + assert.Equal(byte(0), res_reply) + assert.Equal(ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA, err) +} + + +func TestReadBuildResponseRecordReplyValidData(t *testing.T) { + assert := assert.New(t) + + hash := make([]byte, 32) + hash[31] = 0x13 + random_data := make([]byte, 495) + random_data[493] = 0x33 + random_data[494] = 0x74 + reply := byte(37) + data := append(hash, random_data...) + data = append(data, reply) + + res_reply, err := readBuildResponseRecordReply(data) + assert.Equal(reply, res_reply) + assert.Equal(nil, err) +} + +func TestReadBuildResponseRecordTooLittleData(t *testing.T) { + assert := assert.New(t) + + hash := make([]byte, 32) + hash[31] = 0x31 + data := append(hash, 0x01) + build_response_record, err := ReadBuildResponseRecord(data) + + assert.Equal(common.Hash(hash), build_response_record.Hash) + assert.Equal([495]byte{}, build_response_record.RandomData) + assert.Equal(ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA, err) +} + +func TestReadBuildResponseRecordValidData(t *testing.T) { + assert := assert.New(t) + + hash := make([]byte, 32) + hash[31] = 0x12 + random_data := make([]byte, 495) + random_data[493] = 0x33 + random_data[494] = 0x74 + reply := byte(37) + data := append(hash, random_data...) + data = append(data, reply) + + build_response_record, err := ReadBuildResponseRecord(data) + + assert.Equal(common.Hash(hash), build_response_record.Hash) + assert.Equal([495]byte(random_data), build_response_record.RandomData) + assert.Equal(reply, build_response_record.Reply) + assert.Equal(nil, err) +}