Files
indra/pkg/engine/onions/introquery.go
2023-05-31 12:46:53 +01:00

107 lines
3.4 KiB
Go

package onions
import (
"github.com/indra-labs/indra/pkg/crypto"
"github.com/indra-labs/indra/pkg/crypto/nonce"
"github.com/indra-labs/indra/pkg/crypto/sha256"
"github.com/indra-labs/indra/pkg/engine/coding"
"github.com/indra-labs/indra/pkg/engine/magic"
"github.com/indra-labs/indra/pkg/engine/sess"
"github.com/indra-labs/indra/pkg/engine/sessions"
"github.com/indra-labs/indra/pkg/util/splice"
"reflect"
)
const (
IntroQueryMagic = "intq"
IntroQueryLen = magic.Len + nonce.IDLen + crypto.PubKeyLen +
3*sha256.Len + nonce.IVLen*3
)
type IntroQuery struct {
ID nonce.ID
// Ciphers is a set of 3 symmetric ciphers that are to be used in their
// given order over the reply message from the service.
crypto.Ciphers
// Nonces are the nonces to use with the cipher when creating the
// encryption for the reply message,
// they are common with the crypts in the header.
crypto.Nonces
// 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.
Key *crypto.Pub
Onion
}
func (x *IntroQuery) Account(res *sess.Data, sm *sess.Manager, s *sessions.Data, last bool) (skip bool, sd *sessions.Data) {
res.ID = x.ID
res.Billable = append(res.Billable, s.Header.Bytes)
skip = true
return
}
func (x *IntroQuery) Decode(s *splice.Splice) (e error) {
if e = magic.TooShort(s.Remaining(), IntroQueryLen-magic.Len,
IntroQueryMagic); fails(e) {
return
}
s.ReadID(&x.ID).ReadCiphers(&x.Ciphers).ReadNonces(&x.Nonces).
ReadPubkey(&x.Key)
return
}
func (x *IntroQuery) Encode(s *splice.Splice) (e error) {
log.T.S("encoding", reflect.TypeOf(x),
x.ID, x.Key, x.Ciphers, x.Nonces,
)
return x.Onion.Encode(s.
Magic(IntroQueryMagic).
ID(x.ID).Ciphers(x.Ciphers).Nonces(x.Nonces).
Pubkey(x.Key),
)
}
func (x *IntroQuery) GetOnion() interface{} { return x }
func (x *IntroQuery) Handle(s *splice.Splice, p Onion, ng Ngin) (e error) {
ng.GetHidden().Lock()
log.D.Ln(ng.Mgr().GetLocalNodeAddressString(), "handling introquery", x.ID,
x.Key.ToBased32Abbreviated())
var ok bool
var il *IntroAd
if il, ok = ng.GetHidden().KnownIntros[x.Key.ToBytes()]; !ok {
// if the reply is zeroes the querant knows it needs to retry at a
// different relay
il = &IntroAd{}
ng.GetHidden().Unlock()
log.E.Ln("intro not known")
return
}
ng.GetHidden().Unlock()
e = il.Encode(s)
rb := FormatReply(GetRoutingHeaderFromCursor(s), x.Ciphers, x.Nonces,
s.GetAll())
switch on1 := p.(type) {
case *Crypt:
sess := ng.Mgr().FindSessionByHeader(on1.ToPriv)
if sess != nil {
in := sess.Node.RelayRate * s.Len() / 2
out := sess.Node.RelayRate * rb.Len() / 2
ng.Mgr().DecSession(sess.Header.Bytes, in+out, false, "introquery")
}
}
ng.HandleMessage(rb, x)
return
}
func (x *IntroQuery) Len() int { return IntroQueryLen + x.Onion.Len() }
func (x *IntroQuery) Magic() string { return IntroQueryMagic }
func (x *IntroQuery) Wrap(inner Onion) { x.Onion = inner }
func init() { Register(IntroQueryMagic, introQueryGen) }
func introQueryGen() coding.Codec { return &IntroQuery{} }