From 1b94d85a052d29937d9533323cbbb5b2cf3cd80d Mon Sep 17 00:00:00 2001 From: Hayden Parker Date: Tue, 27 Dec 2016 17:56:21 +0000 Subject: [PATCH 1/5] appending delay and extended option to delivery instructions --- lib/tunnel/delivery.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/tunnel/delivery.go b/lib/tunnel/delivery.go index a99e6a9..3616ceb 100644 --- a/lib/tunnel/delivery.go +++ b/lib/tunnel/delivery.go @@ -625,8 +625,20 @@ func maybeAppendHash(di_flag DeliveryInstructions, data, current []byte) (now [] } func maybeAppendDelay(di_flag DeliveryInstructions, data, current []byte) (now []byte, err error) { + delivery_type, _ := di_flag.DeliveryType() + if _, err = DeliveryInstructions(data).Hash(); err == nil { + delay_start := 1 + if delivery_type == DT_TUNNEL { + delay_start = delay_start + 4 + } + if hash, _ := di_flag.Hash(); len(hash) == 32 { + delay_start = delay_start + 32 + } + if err == nil { + now = append(current, data[delay_start]) + } + } return - //if has_delay, _ := di_flag.HasDelay(); has_delay {} } func maybeAppendMessageID(di_flag DeliveryInstructions, di_type int, data, current []byte) (now []byte, err error) { if di_type == FIRST_FRAGMENT { @@ -656,10 +668,15 @@ func maybeAppendMessageID(di_flag DeliveryInstructions, di_type int, data, curre } return } + func maybeAppendExtendedOptions(di_flag DeliveryInstructions, data, current []byte) (now []byte, err error) { - //has_extended_options, _ := di_flag.HasExtendedOptions() + if index, err := DeliveryInstructions(data).extended_options_index(); err != nil { + extended_options_length := common.Integer([]byte{data[index]}) + now = append(current, data[index:index+extended_options_length]...) + } return } + func maybeAppendSize(di_flag DeliveryInstructions, di_type int, data, current []byte) (now []byte, err error) { if di_type == FIRST_FRAGMENT { } else if di_type == FOLLOW_ON_FRAGMENT { From a0bbfac457d4b851162706e8840200e63a3e6f11 Mon Sep 17 00:00:00 2001 From: Hayden Parker Date: Wed, 28 Dec 2016 22:47:52 +0000 Subject: [PATCH 2/5] starting delivery instruction testing --- lib/tunnel/delivery.go | 9 +++--- lib/tunnel/delivery_test.go | 56 +++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 lib/tunnel/delivery_test.go diff --git a/lib/tunnel/delivery.go b/lib/tunnel/delivery.go index 3616ceb..c733783 100644 --- a/lib/tunnel/delivery.go +++ b/lib/tunnel/delivery.go @@ -337,7 +337,7 @@ func (delivery_instructions DeliveryInstructions) Hash() (hash common.Hash, err err = errors.New("DeliveryInstructions is invalid, not contain enough data for hash given type DT_ROUTER") } } else { - err = errors.New("No Hash on DeliveryInstructions not of type DT_TUNNEL or DT_ROUTER") + //err = errors.New("No Hash on DeliveryInstructions not of type DT_TUNNEL or DT_ROUTER") } return } @@ -679,6 +679,10 @@ func maybeAppendExtendedOptions(di_flag DeliveryInstructions, data, current []by func maybeAppendSize(di_flag DeliveryInstructions, di_type int, data, current []byte) (now []byte, err error) { if di_type == FIRST_FRAGMENT { + if index, err := DeliveryInstructions(data).extended_options_index(); err != nil { + extended_options_length := common.Integer([]byte{data[index]}) + now = append(current, data[index+extended_options_length:index+extended_options_length+2]...) + } } else if di_type == FOLLOW_ON_FRAGMENT { if len(data) < 7 { err = errors.New("data is too short to contain size data") @@ -689,9 +693,6 @@ func maybeAppendSize(di_flag DeliveryInstructions, di_type int, data, current [] return } -//delivery_type, _ := di_flag.DeliveryType() -//has_tunnel_id, _ := di_flag.HasTunnelID() - func readDeliveryInstructions(data []byte) (instructions DeliveryInstructions, remainder []byte, err error) { if len(data) < 1 { err = errors.New("no data provided") diff --git a/lib/tunnel/delivery_test.go b/lib/tunnel/delivery_test.go new file mode 100644 index 0000000..e87e1a7 --- /dev/null +++ b/lib/tunnel/delivery_test.go @@ -0,0 +1,56 @@ +package tunnel + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +type DeliveryInstructionsFlags struct { + FirstFragment bool + Type byte + Delay bool +} + +func (dif DeliveryInstructionsFlags) FlagByte() byte { + flag := byte(0x00) + if !dif.FirstFragment { + flag |= 0x01 + } + flag |= dif.Type + if dif.Delay { + flag |= 0x10 + } + return byte(flag) +} + +func validFirstFragmentDeliveryInstructions() []byte { + data := []byte{} + + flag := DeliveryInstructionsFlags{ + FirstFragment: true, + Type: 0x02, + Delay: false, + }.FlagByte() + data = append(data, flag) + + tunnel_id := []byte{0x00, 0x00, 0x00, 0x01} + data = append(data, tunnel_id...) + + hash := make([]byte, 32) + data = append(data, hash...) + + // Add 0 delay + data = append(data, 0) + + message_id := []byte{0x00, 0x00, 0x00, 0x02} + data = append(data, message_id...) + + return data +} + +func TestReadDeliveryInstructions(t *testing.T) { + assert := assert.New(t) + + _, _, err := readDeliveryInstructions(validFirstFragmentDeliveryInstructions()) + assert.Nil(err) +} From c501cb0c65706e1d647a093385d9c67394b54757 Mon Sep 17 00:00:00 2001 From: Hayden Parker Date: Thu, 29 Dec 2016 13:34:01 +0000 Subject: [PATCH 3/5] better parsing of hashes --- lib/tunnel/delivery.go | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/tunnel/delivery.go b/lib/tunnel/delivery.go index c733783..c9458fb 100644 --- a/lib/tunnel/delivery.go +++ b/lib/tunnel/delivery.go @@ -292,6 +292,25 @@ func (delivery_instructions DeliveryInstructions) HasTunnelID() (bool, error) { return di_type == DT_TUNNEL, nil } +func (delivery_instructions DeliveryInstructions) HasHash() (bool, error) { + di_type, err := delivery_instructions.DeliveryType() + if err != nil { + return false, err + } + if di_type == DT_TUNNEL || di_type == DT_ROUTER { + min_size := 33 + if di_type == DT_TUNNEL { + min_size += 4 + } + if len(delivery_instructions) < min_size { + return false, errors.New("Delivery Instructions indicates hash present but has too little data") + } + } else { + return false, nil + } + return true, nil +} + // Return the tunnel ID in this DeliveryInstructions or 0 and an error if the // DeliveryInstructions are not of type DT_TUNNEL. func (delivery_instructions DeliveryInstructions) TunnelID() (tunnel_id uint32, err error) { @@ -337,7 +356,7 @@ func (delivery_instructions DeliveryInstructions) Hash() (hash common.Hash, err err = errors.New("DeliveryInstructions is invalid, not contain enough data for hash given type DT_ROUTER") } } else { - //err = errors.New("No Hash on DeliveryInstructions not of type DT_TUNNEL or DT_ROUTER") + err = errors.New("No Hash on DeliveryInstructions not of type DT_TUNNEL or DT_ROUTER") } return } @@ -610,7 +629,7 @@ func maybeAppendTunnelID(data, current []byte) (now []byte, err error) { func maybeAppendHash(di_flag DeliveryInstructions, data, current []byte) (now []byte, err error) { delivery_type, _ := di_flag.DeliveryType() - if _, err = DeliveryInstructions(data).Hash(); err == nil { + if _, err := DeliveryInstructions(data).HasHash(); err == nil { hash_start := 1 hash_end := 33 if delivery_type == DT_TUNNEL { @@ -626,7 +645,7 @@ func maybeAppendHash(di_flag DeliveryInstructions, data, current []byte) (now [] func maybeAppendDelay(di_flag DeliveryInstructions, data, current []byte) (now []byte, err error) { delivery_type, _ := di_flag.DeliveryType() - if _, err = DeliveryInstructions(data).Hash(); err == nil { + if _, err = DeliveryInstructions(data).HasHash(); err == nil { delay_start := 1 if delivery_type == DT_TUNNEL { delay_start = delay_start + 4 From 22356f8a3a9c3e8e9a6904385ebd456723287c6b Mon Sep 17 00:00:00 2001 From: Hayden Parker Date: Thu, 29 Dec 2016 15:46:25 +0000 Subject: [PATCH 4/5] constants --- lib/tunnel/delivery.go | 35 ++++++++++++++++++++++------------- lib/tunnel/delivery_test.go | 13 ++++++++----- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/lib/tunnel/delivery.go b/lib/tunnel/delivery.go index c9458fb..a526ebb 100644 --- a/lib/tunnel/delivery.go +++ b/lib/tunnel/delivery.go @@ -135,6 +135,16 @@ const ( FOLLOW_ON_FRAGMENT ) +const ( + FLAG_SIZE = 1 + TUNNEL_ID_SIZE = 4 + HASH_SIZE = 32 + DELAY_SIZE = 1 + MESSAGE_ID_SIZE = 4 + EXTENDED_OPTIONS_MIN_SIZE = 2 + SIZE_FIELD_SIZE = 2 +) + type DelayFactor byte type DeliveryInstructions []byte @@ -298,9 +308,9 @@ func (delivery_instructions DeliveryInstructions) HasHash() (bool, error) { return false, err } if di_type == DT_TUNNEL || di_type == DT_ROUTER { - min_size := 33 + min_size := FLAG_SIZE + HASH_SIZE if di_type == DT_TUNNEL { - min_size += 4 + min_size += TUNNEL_ID_SIZE } if len(delivery_instructions) < min_size { return false, errors.New("Delivery Instructions indicates hash present but has too little data") @@ -319,8 +329,8 @@ func (delivery_instructions DeliveryInstructions) TunnelID() (tunnel_id uint32, return } if has_tunnel_id { - if len(delivery_instructions) >= 5 { - tunnel_id = binary.BigEndian.Uint32(delivery_instructions[1:5]) + if len(delivery_instructions) >= FLAG_SIZE+TUNNEL_ID_SIZE { + tunnel_id = binary.BigEndian.Uint32(delivery_instructions[FLAG_SIZE:TUNNEL_ID_SIZE]) } else { err = errors.New("DeliveryInstructions are invalid, too little data for Tunnel ID") } @@ -338,12 +348,11 @@ func (delivery_instructions DeliveryInstructions) Hash() (hash common.Hash, err if err != nil { return } - hash_start := 1 - hash_end := 33 + hash_start := FLAG_SIZE + hash_end := FLAG_SIZE + HASH_SIZE if delivery_type == DT_TUNNEL { - // add 4 bytes for DT_TUNNEL's TunnelID - hash_start := hash_start + 4 - hash_end := hash_end + 4 + hash_start := hash_start + TUNNEL_ID_SIZE + hash_end := hash_end + TUNNEL_ID_SIZE if len(delivery_instructions) >= hash_end { copy(hash[:], delivery_instructions[hash_start:hash_end]) } else { @@ -374,15 +383,15 @@ func (delivery_instructions DeliveryInstructions) Delay() (delay_factor DelayFac return } if di_type == DT_TUNNEL { - if len(delivery_instructions) >= 37 { - delay_factor = DelayFactor(delivery_instructions[37]) + if len(delivery_instructions) >= FLAG_SIZE+TUNNEL_ID_SIZE+HASH_SIZE { + delay_factor = DelayFactor(delivery_instructions[FLAG_SIZE+TUNNEL_ID_SIZE+HASH_SIZE]) } else { err = errors.New("DeliveryInstructions is invalid, does not contain enough data for DelayFactor") return } } else if di_type == DT_ROUTER { - if len(delivery_instructions) >= 36 { - delay_factor = DelayFactor(delivery_instructions[36]) + if len(delivery_instructions) >= FLAG_SIZE+HASH_SIZE { + delay_factor = DelayFactor(delivery_instructions[FLAG_SIZE+HASH_SIZE]) } else { err = errors.New("DeliveryInstructions is invalid, does not contain enough data for DelayFactor") return diff --git a/lib/tunnel/delivery_test.go b/lib/tunnel/delivery_test.go index e87e1a7..092263f 100644 --- a/lib/tunnel/delivery_test.go +++ b/lib/tunnel/delivery_test.go @@ -30,17 +30,20 @@ func validFirstFragmentDeliveryInstructions() []byte { FirstFragment: true, Type: 0x02, Delay: false, - }.FlagByte() - data = append(data, flag) + } + data = append(data, flag.FlagByte()) tunnel_id := []byte{0x00, 0x00, 0x00, 0x01} data = append(data, tunnel_id...) - hash := make([]byte, 32) + hash := make([]byte, HASH_SIZE) data = append(data, hash...) - // Add 0 delay - data = append(data, 0) + if flag.Delay { + data = append(data, 1) + } else { + data = append(data, 0) + } message_id := []byte{0x00, 0x00, 0x00, 0x02} data = append(data, message_id...) From fe3ddad072efcc5adc0ff343c7e3997fec92ca49 Mon Sep 17 00:00:00 2001 From: Hayden Parker Date: Thu, 29 Dec 2016 16:52:57 +0000 Subject: [PATCH 5/5] follow on fragment flag parsing --- lib/tunnel/delivery.go | 42 +++++++++++++++++++++++++++++++++++-- lib/tunnel/delivery_test.go | 12 +++++++++-- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/lib/tunnel/delivery.go b/lib/tunnel/delivery.go index a526ebb..77a24e5 100644 --- a/lib/tunnel/delivery.go +++ b/lib/tunnel/delivery.go @@ -178,13 +178,51 @@ func (delivery_instructions DeliveryInstructions) Type() (int, error) { // Read the integer stored in the 6-1 bits of a FOLLOW_ON_FRAGMENT's flag, indicating // the fragment number. func (delivery_instructions DeliveryInstructions) FragmentNumber() (int, error) { - return 0, nil + di_type, err := delivery_instructions.Type() + if err != nil { + return 0, err + } + /* + Read the 6-1 bits of the Delivery Instructions + to determine the FragmentNumber of Follow On Fragments + + xnnnnnnx + &01111110 bit shift + --------- + 0??????0 >> 1 => Integer(??????) + */ + if di_type == FOLLOW_ON_FRAGMENT { + return common.Integer( + []byte{((delivery_instructions[0] & 0x7e) >> 1)}, + ), nil + } + return 0, errors.New("Fragment Number only exists on FOLLOW_ON_FRAGMENT Delivery Instructions") } // Read the value of the 0 bit of a FOLLOW_ON_FRAGMENT, which is set to 1 to indicate the // last fragment. func (delivery_instructions DeliveryInstructions) LastFollowOnFragment() (bool, error) { - return true, nil + di_type, err := delivery_instructions.Type() + if err != nil { + return false, err + } + /* + Check the 0 bit of the Delivery Instructions + to determine if this is the last Follow On Fragment + + xxxxxxxx + &00000001 + --------- + 0000000? => n + */ + if di_type == FOLLOW_ON_FRAGMENT { + if delivery_instructions[0]&0x01 == 0x01 { + return true, nil + } else { + return false, nil + } + } + return false, errors.New("Last Fragment only exists for FOLLOW_ON_FRAGMENT Delivery Instructions") } // Return the delivery type for these DeliveryInstructions, can be of type diff --git a/lib/tunnel/delivery_test.go b/lib/tunnel/delivery_test.go index 092263f..1e2f323 100644 --- a/lib/tunnel/delivery_test.go +++ b/lib/tunnel/delivery_test.go @@ -1,6 +1,7 @@ package tunnel import ( + "github.com/hkparker/go-i2p/lib/common" "github.com/stretchr/testify/assert" "testing" ) @@ -23,7 +24,7 @@ func (dif DeliveryInstructionsFlags) FlagByte() byte { return byte(flag) } -func validFirstFragmentDeliveryInstructions() []byte { +func validFirstFragmentDeliveryInstructions(mapping common.Mapping) []byte { data := []byte{} flag := DeliveryInstructionsFlags{ @@ -48,12 +49,19 @@ func validFirstFragmentDeliveryInstructions() []byte { message_id := []byte{0x00, 0x00, 0x00, 0x02} data = append(data, message_id...) + data = append(data, mapping...) + return data } func TestReadDeliveryInstructions(t *testing.T) { assert := assert.New(t) - _, _, err := readDeliveryInstructions(validFirstFragmentDeliveryInstructions()) + mapping, _ := common.GoMapToMapping(map[string]string{}) + _, _, err := readDeliveryInstructions( + validFirstFragmentDeliveryInstructions( + mapping, + ), + ) assert.Nil(err) }