mirror of
https://github.com/go-i2p/go-i2p.git
synced 2025-07-04 05:26:51 -04:00
Merge branch 'master' of github.com:hkparker/go-i2p
This commit is contained in:
@ -135,6 +135,16 @@ const (
|
|||||||
FOLLOW_ON_FRAGMENT
|
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 DelayFactor byte
|
||||||
|
|
||||||
type DeliveryInstructions []byte
|
type DeliveryInstructions []byte
|
||||||
@ -168,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
|
// Read the integer stored in the 6-1 bits of a FOLLOW_ON_FRAGMENT's flag, indicating
|
||||||
// the fragment number.
|
// the fragment number.
|
||||||
func (delivery_instructions DeliveryInstructions) FragmentNumber() (int, error) {
|
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
|
// Read the value of the 0 bit of a FOLLOW_ON_FRAGMENT, which is set to 1 to indicate the
|
||||||
// last fragment.
|
// last fragment.
|
||||||
func (delivery_instructions DeliveryInstructions) LastFollowOnFragment() (bool, error) {
|
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
|
// Return the delivery type for these DeliveryInstructions, can be of type
|
||||||
@ -292,6 +340,25 @@ func (delivery_instructions DeliveryInstructions) HasTunnelID() (bool, error) {
|
|||||||
return di_type == DT_TUNNEL, nil
|
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 := FLAG_SIZE + HASH_SIZE
|
||||||
|
if di_type == DT_TUNNEL {
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Return the tunnel ID in this DeliveryInstructions or 0 and an error if the
|
// Return the tunnel ID in this DeliveryInstructions or 0 and an error if the
|
||||||
// DeliveryInstructions are not of type DT_TUNNEL.
|
// DeliveryInstructions are not of type DT_TUNNEL.
|
||||||
func (delivery_instructions DeliveryInstructions) TunnelID() (tunnel_id uint32, err error) {
|
func (delivery_instructions DeliveryInstructions) TunnelID() (tunnel_id uint32, err error) {
|
||||||
@ -300,8 +367,8 @@ func (delivery_instructions DeliveryInstructions) TunnelID() (tunnel_id uint32,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if has_tunnel_id {
|
if has_tunnel_id {
|
||||||
if len(delivery_instructions) >= 5 {
|
if len(delivery_instructions) >= FLAG_SIZE+TUNNEL_ID_SIZE {
|
||||||
tunnel_id = binary.BigEndian.Uint32(delivery_instructions[1:5])
|
tunnel_id = binary.BigEndian.Uint32(delivery_instructions[FLAG_SIZE:TUNNEL_ID_SIZE])
|
||||||
} else {
|
} else {
|
||||||
err = errors.New("DeliveryInstructions are invalid, too little data for Tunnel ID")
|
err = errors.New("DeliveryInstructions are invalid, too little data for Tunnel ID")
|
||||||
}
|
}
|
||||||
@ -319,12 +386,11 @@ func (delivery_instructions DeliveryInstructions) Hash() (hash common.Hash, err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hash_start := 1
|
hash_start := FLAG_SIZE
|
||||||
hash_end := 33
|
hash_end := FLAG_SIZE + HASH_SIZE
|
||||||
if delivery_type == DT_TUNNEL {
|
if delivery_type == DT_TUNNEL {
|
||||||
// add 4 bytes for DT_TUNNEL's TunnelID
|
hash_start := hash_start + TUNNEL_ID_SIZE
|
||||||
hash_start := hash_start + 4
|
hash_end := hash_end + TUNNEL_ID_SIZE
|
||||||
hash_end := hash_end + 4
|
|
||||||
if len(delivery_instructions) >= hash_end {
|
if len(delivery_instructions) >= hash_end {
|
||||||
copy(hash[:], delivery_instructions[hash_start:hash_end])
|
copy(hash[:], delivery_instructions[hash_start:hash_end])
|
||||||
} else {
|
} else {
|
||||||
@ -355,15 +421,15 @@ func (delivery_instructions DeliveryInstructions) Delay() (delay_factor DelayFac
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if di_type == DT_TUNNEL {
|
if di_type == DT_TUNNEL {
|
||||||
if len(delivery_instructions) >= 37 {
|
if len(delivery_instructions) >= FLAG_SIZE+TUNNEL_ID_SIZE+HASH_SIZE {
|
||||||
delay_factor = DelayFactor(delivery_instructions[37])
|
delay_factor = DelayFactor(delivery_instructions[FLAG_SIZE+TUNNEL_ID_SIZE+HASH_SIZE])
|
||||||
} else {
|
} else {
|
||||||
err = errors.New("DeliveryInstructions is invalid, does not contain enough data for DelayFactor")
|
err = errors.New("DeliveryInstructions is invalid, does not contain enough data for DelayFactor")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if di_type == DT_ROUTER {
|
} else if di_type == DT_ROUTER {
|
||||||
if len(delivery_instructions) >= 36 {
|
if len(delivery_instructions) >= FLAG_SIZE+HASH_SIZE {
|
||||||
delay_factor = DelayFactor(delivery_instructions[36])
|
delay_factor = DelayFactor(delivery_instructions[FLAG_SIZE+HASH_SIZE])
|
||||||
} else {
|
} else {
|
||||||
err = errors.New("DeliveryInstructions is invalid, does not contain enough data for DelayFactor")
|
err = errors.New("DeliveryInstructions is invalid, does not contain enough data for DelayFactor")
|
||||||
return
|
return
|
||||||
@ -610,7 +676,7 @@ func maybeAppendTunnelID(data, current []byte) (now []byte, err error) {
|
|||||||
|
|
||||||
func maybeAppendHash(di_flag DeliveryInstructions, data, current []byte) (now []byte, err error) {
|
func maybeAppendHash(di_flag DeliveryInstructions, data, current []byte) (now []byte, err error) {
|
||||||
delivery_type, _ := di_flag.DeliveryType()
|
delivery_type, _ := di_flag.DeliveryType()
|
||||||
if _, err = DeliveryInstructions(data).Hash(); err == nil {
|
if _, err := DeliveryInstructions(data).HasHash(); err == nil {
|
||||||
hash_start := 1
|
hash_start := 1
|
||||||
hash_end := 33
|
hash_end := 33
|
||||||
if delivery_type == DT_TUNNEL {
|
if delivery_type == DT_TUNNEL {
|
||||||
@ -625,8 +691,20 @@ func maybeAppendHash(di_flag DeliveryInstructions, data, current []byte) (now []
|
|||||||
}
|
}
|
||||||
|
|
||||||
func maybeAppendDelay(di_flag DeliveryInstructions, data, current []byte) (now []byte, err error) {
|
func maybeAppendDelay(di_flag DeliveryInstructions, data, current []byte) (now []byte, err error) {
|
||||||
|
delivery_type, _ := di_flag.DeliveryType()
|
||||||
|
if _, err = DeliveryInstructions(data).HasHash(); 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
|
return
|
||||||
//if has_delay, _ := di_flag.HasDelay(); has_delay {}
|
|
||||||
}
|
}
|
||||||
func maybeAppendMessageID(di_flag DeliveryInstructions, di_type int, data, current []byte) (now []byte, err error) {
|
func maybeAppendMessageID(di_flag DeliveryInstructions, di_type int, data, current []byte) (now []byte, err error) {
|
||||||
if di_type == FIRST_FRAGMENT {
|
if di_type == FIRST_FRAGMENT {
|
||||||
@ -656,12 +734,21 @@ func maybeAppendMessageID(di_flag DeliveryInstructions, di_type int, data, curre
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func maybeAppendExtendedOptions(di_flag DeliveryInstructions, data, current []byte) (now []byte, err error) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func maybeAppendSize(di_flag DeliveryInstructions, di_type int, data, current []byte) (now []byte, err error) {
|
func maybeAppendSize(di_flag DeliveryInstructions, di_type int, data, current []byte) (now []byte, err error) {
|
||||||
if di_type == FIRST_FRAGMENT {
|
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 {
|
} else if di_type == FOLLOW_ON_FRAGMENT {
|
||||||
if len(data) < 7 {
|
if len(data) < 7 {
|
||||||
err = errors.New("data is too short to contain size data")
|
err = errors.New("data is too short to contain size data")
|
||||||
@ -672,9 +759,6 @@ func maybeAppendSize(di_flag DeliveryInstructions, di_type int, data, current []
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//delivery_type, _ := di_flag.DeliveryType()
|
|
||||||
//has_tunnel_id, _ := di_flag.HasTunnelID()
|
|
||||||
|
|
||||||
func readDeliveryInstructions(data []byte) (instructions DeliveryInstructions, remainder []byte, err error) {
|
func readDeliveryInstructions(data []byte) (instructions DeliveryInstructions, remainder []byte, err error) {
|
||||||
if len(data) < 1 {
|
if len(data) < 1 {
|
||||||
err = errors.New("no data provided")
|
err = errors.New("no data provided")
|
||||||
|
67
lib/tunnel/delivery_test.go
Normal file
67
lib/tunnel/delivery_test.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package tunnel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hkparker/go-i2p/lib/common"
|
||||||
|
"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(mapping common.Mapping) []byte {
|
||||||
|
data := []byte{}
|
||||||
|
|
||||||
|
flag := DeliveryInstructionsFlags{
|
||||||
|
FirstFragment: true,
|
||||||
|
Type: 0x02,
|
||||||
|
Delay: false,
|
||||||
|
}
|
||||||
|
data = append(data, flag.FlagByte())
|
||||||
|
|
||||||
|
tunnel_id := []byte{0x00, 0x00, 0x00, 0x01}
|
||||||
|
data = append(data, tunnel_id...)
|
||||||
|
|
||||||
|
hash := make([]byte, HASH_SIZE)
|
||||||
|
data = append(data, hash...)
|
||||||
|
|
||||||
|
if flag.Delay {
|
||||||
|
data = append(data, 1)
|
||||||
|
} else {
|
||||||
|
data = append(data, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
mapping, _ := common.GoMapToMapping(map[string]string{})
|
||||||
|
_, _, err := readDeliveryInstructions(
|
||||||
|
validFirstFragmentDeliveryInstructions(
|
||||||
|
mapping,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
assert.Nil(err)
|
||||||
|
}
|
Reference in New Issue
Block a user