Files
indra/pkg/wire/exit/exit.go

96 lines
3.1 KiB
Go

package exit
import (
"github.com/davecgh/go-spew/spew"
"github.com/indra-labs/indra"
"github.com/indra-labs/indra/pkg/crypto/nonce"
"github.com/indra-labs/indra/pkg/crypto/sha256"
log2 "github.com/indra-labs/indra/pkg/proc/log"
"github.com/indra-labs/indra/pkg/types"
"github.com/indra-labs/indra/pkg/util/slice"
"github.com/indra-labs/indra/pkg/wire/magicbytes"
)
const (
MagicString = "ex"
Len = magicbytes.Len + slice.Uint16Len + 3*sha256.Len +
slice.Uint32Len + nonce.IVLen*3
)
var (
log = log2.GetLogger(indra.PathBase)
check = log.E.Chk
Magic = slice.Bytes(MagicString)
_ types.Onion = &OnionSkin{}
)
// OnionSkin exit messages are the layer of a message after two Forward packets
// that provides an exit address and
type OnionSkin struct {
// Port identifies the type of service as well as being the port used by
// the service to be relayed to. Notice there is no IP address, this is
// because Indranet only forwards to exits of decentralised services
// also running on the same machine. This service could be a proxy, of
// course, if configured this way. This could be done by tunneling from
// a local Socks5 proxy into Indranet and the exit node also having
// this.
Port uint16
// Ciphers is a set of 3 symmetric ciphers that are to be used in their
// given order over the reply message from the service.
Ciphers [3]sha256.Hash
// Nonces are the nonces to use with the cipher when creating the
// encryption for the reply message.
Nonces [3]nonce.IV
// Bytes are the message to be passed to the exit service.
slice.Bytes
types.Onion
}
func (x *OnionSkin) String() string {
return spew.Sdump(x.Port, x.Ciphers, x.Nonces, x.Bytes.ToBytes())
}
func (x *OnionSkin) Inner() types.Onion { return x.Onion }
func (x *OnionSkin) Insert(o types.Onion) { x.Onion = o }
func (x *OnionSkin) Len() int {
return Len + x.Bytes.Len() + x.Onion.Len()
}
func (x *OnionSkin) Encode(b slice.Bytes, c *slice.Cursor) {
copy(b[*c:c.Inc(magicbytes.Len)], Magic)
port := slice.NewUint16()
slice.EncodeUint16(port, int(x.Port))
copy(b[*c:c.Inc(slice.Uint16Len)], port)
copy(b[*c:c.Inc(sha256.Len)], x.Ciphers[0][:])
copy(b[*c:c.Inc(sha256.Len)], x.Ciphers[1][:])
copy(b[*c:c.Inc(sha256.Len)], x.Ciphers[2][:])
copy(b[*c:c.Inc(nonce.IVLen)], x.Nonces[0][:])
copy(b[*c:c.Inc(nonce.IVLen)], x.Nonces[1][:])
copy(b[*c:c.Inc(nonce.IVLen)], x.Nonces[2][:])
bytesLen := slice.NewUint32()
slice.EncodeUint32(bytesLen, len(x.Bytes))
copy(b[*c:c.Inc(slice.Uint32Len)], bytesLen)
copy(b[*c:c.Inc(len(x.Bytes))], x.Bytes)
x.Onion.Encode(b, c)
}
func (x *OnionSkin) Decode(b slice.Bytes, c *slice.Cursor) (e error) {
if len(b[*c:]) < Len-magicbytes.Len {
return magicbytes.TooShort(len(b[*c:]), Len-magicbytes.Len, string(Magic))
}
x.Port = uint16(slice.DecodeUint16(b[*c:c.Inc(slice.Uint16Len)]))
for i := range x.Ciphers {
bytes := b[*c:c.Inc(sha256.Len)]
copy(x.Ciphers[i][:], bytes)
bytes.Zero()
}
for i := range x.Nonces {
bytes := b[*c:c.Inc(nonce.IVLen)]
copy(x.Nonces[i][:], bytes)
bytes.Zero()
}
bytesLen := slice.DecodeUint32(b[*c:c.Inc(slice.Uint32Len)])
x.Bytes = b[*c:c.Inc(bytesLen)]
return
}