Advertisement
Ryggs

dPaste

Mar 22nd, 2020
386
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 8.48 KB | None | 0 0
  1. import (
  2.     "crypto/rand"
  3.     "errors"
  4.     "os"
  5.     "plugin"
  6.     "reflect"
  7.     "sync"
  8.     "unsafe"
  9. )
  10. // This is the actual module we have loaded
  11. type ModQuery struct {
  12.     Module       *plugin.Plugin
  13.     MethodMap    map[string]reflect.Value
  14.     ParamMap     map[string][]reflect.Value
  15.     Result       []interface{}
  16.     Error        error
  17.     ReplyTracker chan interface{}
  18.     ModuleName   string
  19. }
  20. // This returns replies from function calls
  21. type FunctionReply struct {
  22.     ModuleName    string
  23.     FunctionHash  [16]byte
  24.     ReturnData    []interface{}
  25.     OutputChannel chan []interface{}
  26.     Error         error
  27. }
  28. // This structure contains all the loaded modules
  29. type LoadedModules struct {
  30.     Loaded        map[string]*ModQuery
  31.     InUseMap      map[string]bool
  32.     ActiveQueries map[string]map[[16]byte]bool
  33.     Signal        chan string
  34.     ReplyTracker  chan interface{}
  35.     Mutex         *sync.Mutex
  36. }
  37. type CallTrack struct {
  38.     ModuleName string
  39.     Hash       [16]byte
  40. }
  41. // Create the overarching module handler
  42. func NewModuleHandler() *LoadedModules {
  43.     return &LoadedModules{
  44.         Loaded:        make(map[string]*ModQuery),
  45.         Signal:        make(chan string),
  46.         InUseMap:      make(map[string]bool),
  47.         ReplyTracker:  make(chan interface{}),
  48.         ActiveQueries: make(map[string]map[[16]byte]bool),
  49.         Mutex:         &sync.Mutex{},
  50.     }
  51. }
  52. // Create a new query for a loaded module
  53. func NewQuery(ModuleName string, ReplyTracker chan interface{}) *ModQuery {
  54.     return &ModQuery{
  55.         MethodMap:    make(map[string]reflect.Value),
  56.         ParamMap:     make(map[string][]reflect.Value),
  57.         ReplyTracker: ReplyTracker,
  58.         ModuleName:   ModuleName,
  59.     }
  60. }
  61. // Handle replies we receive
  62. func (lm *LoadedModules) ReplyHandler(InputChannel chan interface{}) {
  63.     var GotReply = false
  64.     for {
  65.         select {
  66.         case input := <-InputChannel:
  67.             switch input.(type) {
  68.             case *FunctionReply:
  69.                 fr := input.(*FunctionReply)
  70.                 lm.Mutex.Lock()
  71.                 if mod, ok := lm.ActiveQueries[fr.ModuleName]; ok {
  72.                     if _, ok := mod[fr.FunctionHash]; ok {
  73.                         GotReply = true
  74.                     }
  75.                 }
  76.                 lm.Mutex.Unlock()
  77.             case *CallTrack:
  78.                 lm.Mutex.Lock()
  79.                 ct := input.(*CallTrack)
  80.                 if _, ok := lm.ActiveQueries[ct.ModuleName]; !ok {
  81.                     lm.ActiveQueries[ct.ModuleName] = make(map[[16]byte]bool)
  82.                 }
  83.                 lm.ActiveQueries[ct.ModuleName][ct.Hash] = true
  84.                 lm.Mutex.Unlock()
  85.             }
  86.             if GotReply {
  87.                 fr := input.(*FunctionReply)
  88.                 fr.OutputChannel <- fr.ReturnData
  89.                 lm.Mutex.Lock()
  90.                 delete(lm.ActiveQueries[fr.ModuleName], fr.FunctionHash)
  91.                 if len(lm.ActiveQueries[fr.ModuleName]) == 0 {
  92.                     lm.InUseMap[fr.ModuleName] = false
  93.                 }
  94.                 lm.Mutex.Unlock()
  95.             }
  96.         }
  97.     }
  98. }
  99. // Load a module from a file - this should be build with --buildmode=plugin
  100. func (lm *LoadedModules) AddModule(fName, mName string) error {
  101.     var err error
  102.     if _, modLoaded := lm.Loaded[mName]; modLoaded {
  103.         return errors.New("module was already loaded")
  104.     }
  105.     if _, err := os.Stat(fName); err != nil {
  106.         if os.IsNotExist(err) {
  107.             return errors.New("specified module doesnt exist")
  108.         }
  109.         return errors.New("error getting module file data")
  110.     }
  111.     NewMod := NewQuery(mName, lm.ReplyTracker)
  112.     if NewMod.Module, err = plugin.Open(fName); err != nil {
  113.         return err
  114.     }
  115.     PlugMap := reflect.ValueOf(NewMod).Elem().Field(3)
  116.     MapValues := reflect.NewAt(PlugMap.Type(), unsafe.Pointer(PlugMap.UnsafeAddr())).Elem()
  117.     MethodMap := MapValues.Interface().(map[string]interface{})
  118.     for MethodName, Method := range MethodMap {
  119.         if reflect.ValueOf(Method).Kind() == reflect.Func {
  120.             err := NewMod.addMethod(MethodName, reflect.ValueOf(Method))
  121.             if err != nil {
  122.                 d.Log(LogHiveSlave, "Failed to load method from module: [s]: %v", MethodName, err)
  123.             }
  124.         }
  125.     }
  126.     lm.Mutex.Lock()
  127.     lm.Loaded[mName] = NewMod
  128.     return nil
  129. }
  130. // Remove a module that's been added
  131. func (lm *LoadedModules) RemoveModule(mName string) {
  132.     var RemovalOk = false
  133.     lm.Mutex.Lock()
  134.     if _, modLoaded := lm.Loaded[mName]; modLoaded {
  135.         if Used, Exists := lm.InUseMap[mName]; Exists && !Used {
  136.             RemovalOk = true
  137.         }
  138.     }
  139.     if RemovalOk {
  140.         lm.Loaded[mName] = nil
  141.         delete(lm.Loaded, mName)
  142.         delete(lm.InUseMap, mName)
  143.         delete(lm.ActiveQueries, mName)
  144.     }
  145.     lm.Mutex.Unlock()
  146. }
  147. // Simplistic way to generate a hash for function call tracking
  148. func NewHash() [16]byte {
  149.     var result [16]byte
  150.     var HashBytes = make([]byte, 8)
  151.     _, _ = rand.Read(HashBytes)
  152.     copy((*[8]byte)(unsafe.Pointer(&result[0]))[:], HashBytes)
  153.     return result
  154. }
  155. // Execute a function from the specific module
  156. func (lm *LoadedModules) ExecuteFunc(
  157.     Method,
  158.     Module string,
  159.     retChan chan []interface{},
  160.     parameters ...interface{}) error {
  161.     var mod *ModQuery
  162.     var verified bool
  163.     if mod, verified = lm.Loaded[Module]; !verified {
  164.         return errors.New("module not loaded")
  165.     } else {
  166.         QueryHash := NewHash()
  167.         lm.ReplyTracker <- &CallTrack{
  168.             ModuleName: Module,
  169.             Hash:       QueryHash,
  170.         }
  171.         go mod.ExecuteMethod(Method, retChan, QueryHash, parameters)
  172.         return nil
  173.     }
  174. }
  175. // Add a method from a module to a point where it is executable
  176. func (q *ModQuery) addMethod(mName string, mFunc reflect.Value) error {
  177.     if mFunc.Kind() != reflect.Func {
  178.         return errors.New("need a function as an input")
  179.     } else {
  180.         q.MethodMap[mName] = mFunc
  181.     }
  182.     return nil
  183. }
  184. func (q *ModQuery) ExecuteMethod(
  185.     Method string, ReturnChan chan []interface{}, Hash [16]byte, params ...interface{}) {
  186.     var staticParamCount int
  187.     if f, haveFunc := q.MethodMap[Method]; haveFunc {
  188.         if len(params) > 0 {
  189.             // Generate an array of parameters as reflection values
  190.             ParameterValues := generateParameters(params)
  191.             // Get the type of function we will be executing so we can pass its input parameters
  192.             funcType := reflect.TypeOf(f.Interface())
  193.             // Now check if this function is varadic
  194.             if funcType.IsVariadic() {
  195.                 // Get the type we need to input for varadic parameters
  196.                 vType := funcType.In(funcType.NumIn() - 1)
  197.                 staticParamCount = funcType.NumIn() - 1
  198.                 if len(ParameterValues) < staticParamCount {
  199.                     newErr := errors.New("incorrect parameter count")
  200.                     q.ReplyTracker <- FuncReplyError(q.ModuleName, Hash, newErr, ReturnChan)
  201.                     return
  202.                 }
  203.                 if len(ParameterValues) > staticParamCount {
  204.                     vParams := ParameterValues[staticParamCount:]
  205.                     for _, vp := range vParams {
  206.                         if reflect.SliceOf(vp.Type()) != vType {
  207.                             newErr := errors.New("incorrectly type varadic argument")
  208.                             q.ReplyTracker <- FuncReplyError(q.ModuleName, Hash, newErr, ReturnChan)
  209.                             return
  210.                         }
  211.                     }
  212.                 }
  213.             } else {
  214.                 // Function was not varadic, verify function input arguments
  215.                 staticParamCount = funcType.NumIn()
  216.                 if len(ParameterValues) != staticParamCount {
  217.                     newErr := errors.New("invalid parameter count to non-varadic function")
  218.                     q.ReplyTracker <- FuncReplyError(q.ModuleName, Hash, newErr, ReturnChan)
  219.                     return
  220.                 }
  221.             }
  222.             // Verify the typing of static parameters
  223.             for i := 0; i < staticParamCount; i++ {
  224.                 if funcType.In(i).Kind() != ParameterValues[i].Kind() {
  225.                     newErr := errors.New("invalid static parameter type")
  226.                     q.ReplyTracker <- FuncReplyError(q.ModuleName, Hash, newErr, ReturnChan)
  227.                     return
  228.                 }
  229.             }
  230.             go q.SendResults(Hash, ReturnChan, f.Call(ParameterValues))
  231.         } else {
  232.             go q.SendResults(Hash, ReturnChan, f.Call([]reflect.Value{}))
  233.         }
  234.     } else {
  235.         newErr := errors.New("method not found")
  236.         q.ReplyTracker <- FuncReplyError(q.ModuleName, Hash, newErr, ReturnChan)
  237.     }
  238. }
  239. // Convert a slice of interfaces to a slice of reflect.Value's
  240. func generateParameters(p []interface{}) []reflect.Value {
  241.     var result = make([]reflect.Value, len(p))
  242.     for i, param := range p {
  243.         result[i] = reflect.ValueOf(param)
  244.     }
  245.     return result
  246. }
  247. // Generate an error function reply
  248. func FuncReplyError(mn string, h [16]byte, err error, Out chan []interface{}) *FunctionReply {
  249.     return &FunctionReply{
  250.         ModuleName:    mn,
  251.         FunctionHash:  h,
  252.         ReturnData:    nil,
  253.         OutputChannel: Out,
  254.         Error:         err,
  255.     }
  256. }
  257. // SendResults sends the results of a called function to the reply tracker
  258. func (q *ModQuery) SendResults(Hash [16]byte, Out chan []interface{}, FuncResult []reflect.Value) {
  259.     result := &FunctionReply{
  260.         ModuleName:    q.ModuleName,
  261.         FunctionHash:  Hash,
  262.         OutputChannel: Out,
  263.         Error:         nil,
  264.     }
  265.     if len(FuncResult) > 0 {
  266.         result.ReturnData = make([]interface{}, len(FuncResult))
  267.         for i, r := range FuncResult {
  268.             result.ReturnData[i] = r.Interface()
  269.         }
  270.     }
  271.     q.ReplyTracker <- result
  272. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement