From 3d436e9c7c6b9c1fb430e9cb1f0f28fc9aaea0cf Mon Sep 17 00:00:00 2001 From: David Vennik Date: Sun, 11 Dec 2022 14:18:08 +0100 Subject: [PATCH] Stubbed in wire message types and interface --- pkg/client/client_test.go | 4 +- pkg/wire/wire.go | 257 +++++++++++++++++++++++++++++++++----- version.go | 8 +- 3 files changed, 233 insertions(+), 36 deletions(-) diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 8f7dfcf7..a717c60f 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -90,7 +90,7 @@ func TestClient_GenerateCircuit(t *testing.T) { IP: ci.Hops[len(ci.Hops)-i-1].IP, Message: lastMsg, } - rmm := rm.Serialize() + rmm := rm.Encode() ep := message.EP{ To: address. FromPubKey(ci.Hops[len(ci.Hops)-i-1].Key), @@ -158,7 +158,7 @@ func TestClient_GenerateCircuit(t *testing.T) { t.Error(e) t.FailNow() } - if rm, e = wire.ToReturnMessage(msg); check(e) { + if rm, e = wire.ToForward(msg); check(e) { t.Error(e) t.FailNow() } diff --git a/pkg/wire/wire.go b/pkg/wire/wire.go index 53ed8ed7..fd6b6f27 100644 --- a/pkg/wire/wire.go +++ b/pkg/wire/wire.go @@ -6,22 +6,47 @@ import ( "reflect" "github.com/Indra-Labs/indra/pkg/ifc" + "github.com/Indra-Labs/indra/pkg/key/pub" + "github.com/Indra-Labs/indra/pkg/nonce" ) -type MessageMagic byte +// MagicLen is 3 to make it nearly impossible that the wrong cipher will yield a +// valid Magic string as listed below. +const MagicLen = 3 -type Message interface{} +type MessageMagic string -const ( - ForwardMagic MessageMagic = iota - ExitMagic - ReturnMagic +func GetMagic(s string) (mm MessageMagic) { + return MessageMagic(s[:MagicLen]) +} + +type Message interface { + Encode() (o ifc.Message) +} + +var ( + ForwardMagic = MessageMagic("fwd") + ExitMagic = MessageMagic("exi") + ReturnMagic = MessageMagic("rtn") + CipherMagic = MessageMagic("cif") + PurchaseMagic = MessageMagic("prc") + SessionMagic = MessageMagic("ses") ) func Serialize(message interface{}) (b ifc.Message, e error) { switch m := message.(type) { case Forward: - b = m.Serialize() + b = m.Encode() + case Exit: + + case Return: + + case Cipher: + + case Purchase: + + case Session: + default: e = fmt.Errorf("unknown type %v", reflect.TypeOf(m)) } @@ -29,21 +54,22 @@ func Serialize(message interface{}) (b ifc.Message, e error) { } func Deserialize(b ifc.Message) (out Message, e error) { - msgMagic := MessageMagic(b[0]) - switch msgMagic { + mm := MessageMagic(b[:MagicLen]) + switch mm { case ForwardMagic: - out, e = DeserializeReturnMessage(b) - } - return -} + out, e = DecodeForward(b) + case ExitMagic: + + case ReturnMagic: + + case CipherMagic: + + case PurchaseMagic: + + case SessionMagic: -func ToReturnMessage(msg Message) (rm *Forward, e error) { - switch r := msg.(type) { - case *Forward: - rm = r default: - e = fmt.Errorf("incorrect type returned %v expected %v", - reflect.TypeOf(r), reflect.TypeOf(&Forward{})) + e = fmt.Errorf("unknown message magic '%s'", mm) } return } @@ -54,28 +80,199 @@ type Forward struct { ifc.Message } -func (rm *Forward) Serialize() (o ifc.Message) { +func (rm *Forward) Encode() (o ifc.Message) { ipLen := len(rm.IP) totalLen := 1 + ipLen + len(rm.Message) + 1 o = make(ifc.Message, totalLen) - o[0] = byte(ForwardMagic) - o[1] = byte(ipLen) - copy(o[2:ipLen+2], rm.IP) - copy(o[ipLen+2:], rm.Message) + copy(o[:MagicLen], ForwardMagic) + o[MagicLen] = byte(ipLen) + copy(o[MagicLen+1:MagicLen+ipLen+2], rm.IP) + copy(o[MagicLen+ipLen+2:], rm.Message) return } -func DeserializeReturnMessage(msg ifc.Message) (rm *Forward, e error) { - ipLen := int(msg[1]) +func DecodeForward(msg ifc.Message) (rm *Forward, e error) { + ipLen := int(msg[MagicLen]) rm = &Forward{ - IP: net.IP(msg[2 : 2+ipLen]), - Message: msg[2+ipLen:], + IP: net.IP(msg[MagicLen+1 : MagicLen+1+ipLen]), + Message: msg[MagicLen+1+ipLen:], } return } -type Exit struct { +// ToForward safely asserts the type of Message to be a Forward message. +func ToForward(msg Message) (f *Forward, e error) { + switch t := msg.(type) { + case *Forward: + f = t + default: + e = fmt.Errorf("incorrect type returned %v expected %v", + reflect.TypeOf(t), reflect.TypeOf(&Forward{})) + } + return } -type Return struct { +// Exit messages are the layer of a message after two Forward packets that +// provides an exit address and +type Exit 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. + Port uint16 + // Cipher is a set of 3 symmetric ciphers that are to be used in their + // given order over the reply message from the service. + Cipher [3][32]byte + // Return is the encoded message with the three hops using the Return + // keys for the relevant relays, encrypted progressively. Note that this + // message uses a different Cipher than the one above + Return ifc.Message + ifc.Message +} + +func (rm *Exit) Encode() (o ifc.Message) { + return +} + +func DecodeExit(msg ifc.Message) (rm *Exit, e error) { + return +} + +// ToExit safely asserts the type of Message to be an Exit message. +func ToExit(msg Message) (x *Exit, e error) { + switch t := msg.(type) { + case *Exit: + x = t + default: + e = fmt.Errorf("incorrect type returned %v expected %v", + reflect.TypeOf(t), reflect.TypeOf(x)) + } + return +} + +// Return messages are distinct from Forward messages in that the header +// encryption uses a different secret than the payload. Relays identify this by +// encrypting the first 16 bytes of the header and if one of the magic bytes is +// not found +type Return struct { + nonce.ID + // IP is the address of the next relay in the return leg of a circuit. + net.IP + ifc.Message +} + +func (rm *Return) Encode() (o ifc.Message) { + return +} + +func DecodeReturn(msg ifc.Message) (rm *Return, e error) { + return +} + +// ToReturn safely asserts the type of Message to be an Return message. +func ToReturn(msg Message) (rm *Return, e error) { + switch r := msg.(type) { + case *Return: + rm = r + default: + e = fmt.Errorf("incorrect type returned %v expected %v", + reflect.TypeOf(r), reflect.TypeOf(rm)) + } + return +} + +// Cipher delivers a public key to be used in association with a Return with the +// matching ID. This is wrapped in two Forward messages and contains two layers +// of Forward messages, ensuring that the node cannot discover where this comes +// from but allows a Return public key to be provided for a Purchase. +type Cipher struct { + nonce.ID + Key pub.Bytes + Forward +} + +func (rm *Cipher) Encode() (o ifc.Message) { + return +} + +func DecodeCipher(msg ifc.Message) (rm *Cipher, e error) { + return +} + +// ToCipher safely asserts the type of Message to be a Cipher message. +func ToCipher(msg Message) (c *Cipher, e error) { + switch t := msg.(type) { + case *Cipher: + c = t + default: + e = fmt.Errorf("incorrect type returned %v expected %v", + reflect.TypeOf(t), reflect.TypeOf(c)) + } + return +} + +// Purchase is a message that is sent after first forwarding a Lighting payment +// of an amount corresponding to the number of bytes requested based on the +// price advertised for Exit traffic by a relay. The Receipt is the confirmation +// after requesting an Invoice for the amount and then paying it. +// +// This message contains a Return message, which enables payments to proxy +// forwards through two hops to the router that will issue the Session, plus two +// more Return layers for carrying the Session back to the client. +type Purchase struct { + Bytes int + Receipt ifc.Message + Return +} + +func (rm *Purchase) Encode() (o ifc.Message) { + return +} + +func DecodePurchase(msg ifc.Message) (rm *Purchase, e error) { + return +} + +// ToPurchase safely asserts the type of Message to be a Purchase message. +func ToPurchase(msg Message) (p *Purchase, e error) { + switch t := msg.(type) { + case *Purchase: + p = t + default: + e = fmt.Errorf("incorrect type returned %v expected %v", + reflect.TypeOf(t), reflect.TypeOf(p)) + } + return +} + +// Session is a message containing two public keys which identify to a relay the +// session to account bytes on, this is wrapped in two Return message layers by +// the seller. Forward keys are used for encryption in Forward and Exit +// messages, and Return keys are separate and are only known to the client and +// relay that issues a Session, ensuring that the Exit cannot see the inner +// layers of the Return messages. +type Session struct { + Forward pub.Bytes + Return pub.Bytes +} + +func (rm *Session) Encode() (o ifc.Message) { + return +} + +func DecodeSession(msg ifc.Message) (rm *Session, e error) { + return +} + +// ToSession safely asserts the type of Message to be a Purchase message. +func ToSession(msg Message) (s *Session, e error) { + switch t := msg.(type) { + case *Session: + s = t + default: + e = fmt.Errorf("incorrect type returned %v expected %v", + reflect.TypeOf(t), reflect.TypeOf(s)) + } + return } diff --git a/version.go b/version.go index 8a5dad5a..89c78958 100644 --- a/version.go +++ b/version.go @@ -13,11 +13,11 @@ var ( // GitRef is the gitref, as in refs/heads/branchname. GitRef = "refs/heads/main" // ParentGitCommit is the commit hash of the parent HEAD. - ParentGitCommit = "9030a2f70411a2df3229a26e8114410cacbb35e3" + ParentGitCommit = "70ca966817cddb2e6916141b330c8764187c2b32" // BuildTime stores the time when the current binary was built. - BuildTime = "2022-12-10T15:24:46+01:00" + BuildTime = "2022-12-11T14:18:08+01:00" // SemVer lists the (latest) git tag on the build. - SemVer = "v0.0.177" + SemVer = "v0.0.178" // PathBase is the path base returned from runtime caller. PathBase = "/home/loki/src/github.com/Indra-Labs/indra/" // Major is the major number from the tag. @@ -25,7 +25,7 @@ var ( // Minor is the minor number from the tag. Minor = 0 // Patch is the patch version number from the tag. - Patch = 177 + Patch = 178 ) // Version returns a pretty printed version information string.