sock.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. package daemon
  2. import (
  3. "bytes"
  4. _ "embed"
  5. "fmt"
  6. "io"
  7. "log"
  8. "net"
  9. "os"
  10. "os/signal"
  11. "syscall"
  12. "git.aetherial.dev/aeth/yosai/pkg/config"
  13. daemonproto "git.aetherial.dev/aeth/yosai/pkg/daemon-proto"
  14. "git.aetherial.dev/aeth/yosai/pkg/keytags"
  15. "git.aetherial.dev/aeth/yosai/pkg/secrets/keyring"
  16. )
  17. type Context struct {
  18. conn net.Listener
  19. keyring *keyring.ApiKeyRing
  20. Keytags keytags.Keytagger
  21. routes map[string]Router
  22. sockPath string
  23. Config *config.Configuration
  24. servers []config.VpnServer
  25. rwBuffer bytes.Buffer
  26. stream io.Writer
  27. }
  28. /*
  29. Show all of the route information for the context
  30. :param msg: a message to parse from the daemon socket
  31. */
  32. func (c *Context) ShowRoutesHandler(msg daemonproto.SockMessage) daemonproto.SockMessage {
  33. var data string
  34. for k, v := range c.routes {
  35. data = data + k + "\n"
  36. routes := v.Routes()
  37. for i := range routes {
  38. data = data + "\u0009" + string(i) + "\n"
  39. }
  40. data = data + "\n"
  41. }
  42. return *daemonproto.NewSockMessage(daemonproto.MsgResponse, daemonproto.REQUEST_OK, []byte(data))
  43. }
  44. /*
  45. Context router
  46. */
  47. type ContextRouter struct {
  48. routes map[daemonproto.Method]func(daemonproto.SockMessage) daemonproto.SockMessage
  49. }
  50. func (c *ContextRouter) Register(method daemonproto.Method, callable func(daemonproto.SockMessage) daemonproto.SockMessage) {
  51. c.routes[method] = callable
  52. }
  53. func (c *ContextRouter) Routes() map[daemonproto.Method]func(daemonproto.SockMessage) daemonproto.SockMessage {
  54. return c.routes
  55. }
  56. func NewContextRouter() *ContextRouter {
  57. return &ContextRouter{routes: map[daemonproto.Method]func(daemonproto.SockMessage) daemonproto.SockMessage{}}
  58. }
  59. /*
  60. Write a message back to the caller
  61. */
  62. func (c *Context) Respond(conn net.Conn) {
  63. conn.Write(c.rwBuffer.Bytes())
  64. }
  65. /*
  66. Log wrapper for the context struct
  67. :param data: string arguments to send to the logger
  68. */
  69. func (c *Context) Log(msg ...string) {
  70. dMsg := []string{"daemon.Context:"}
  71. dMsg = append(dMsg, msg...)
  72. c.Config.Log(dMsg...)
  73. }
  74. func (c *Context) Handle(conn net.Conn) {
  75. defer conn.Close()
  76. b := make([]byte, 2048)
  77. nr, err := conn.Read(b)
  78. if err != nil {
  79. c.Log(err.Error())
  80. return
  81. }
  82. req := c.parseRequest(b[0:nr])
  83. out := c.resolveRoute(req)
  84. _, err = conn.Write(daemonproto.Marshal(out))
  85. if err != nil {
  86. c.Log(err.Error())
  87. return
  88. }
  89. }
  90. /*
  91. spawns subroutines to listen for different syscalls
  92. */
  93. func (c *Context) handleSyscalls() {
  94. // Cleanup the sockfile.
  95. chanSig := make(chan os.Signal, 1)
  96. signal.Notify(chanSig, os.Interrupt, syscall.SIGTERM)
  97. go func() {
  98. <-chanSig
  99. os.Remove(c.sockPath)
  100. os.Exit(1)
  101. }()
  102. }
  103. /*
  104. Open a daemon context pointer
  105. */
  106. func NewContext(path string, rdr io.Writer, apiKeyring *keyring.ApiKeyRing, conf *config.Configuration) *Context {
  107. sock, err := net.Listen("unix", path)
  108. if err != nil {
  109. log.Fatal(err)
  110. }
  111. routes := map[string]Router{}
  112. buf := make([]byte, 1024)
  113. return &Context{conn: sock, sockPath: path, rwBuffer: *bytes.NewBuffer(buf), stream: rdr, keyring: apiKeyring,
  114. routes: routes, Config: conf, Keytags: keytags.ConstKeytag{}}
  115. }
  116. /*
  117. Register a function to the daemons function router
  118. :param name: the name to map the function to. This will dictate how the CLI will resolve a keyword to the target function
  119. :param callable: the callable that will be executed when the keyword from 'name' is passed to the CLI
  120. */
  121. func (c *Context) Register(name string, router Router) {
  122. c.routes[name] = router
  123. }
  124. /*
  125. Hold the execution context open and listen for input
  126. */
  127. func (c *Context) ListenAndServe() {
  128. c.handleSyscalls()
  129. for {
  130. conn, err := c.conn.Accept()
  131. if err != nil {
  132. log.Fatal(err)
  133. }
  134. go c.Handle(conn)
  135. }
  136. }
  137. /*
  138. Validate and parse a stream from the unix socket and return an Action
  139. :param msg: a byte array with the action and arguments
  140. */
  141. func (c *Context) parseRequest(msg []byte) daemonproto.SockMessage {
  142. c.Log("Recieved request to parse action. ", string(msg))
  143. return daemonproto.Unmarshal(msg)
  144. }
  145. /*
  146. Resolve an action to a function
  147. :param action: a parsed action from the sock stream
  148. */
  149. func (c *Context) resolveRoute(req daemonproto.SockMessage) daemonproto.SockMessage {
  150. router, ok := c.routes[req.Target]
  151. if !ok {
  152. err := InvalidAction{Msg: "Invalid Action", Action: req.Target}
  153. c.Log("Error finding a router for target: ", req.Target)
  154. return daemonproto.SockMessage{StatusMsg: daemonproto.UNRESOLVEABLE, Body: []byte(err.Error())}
  155. }
  156. method, err := daemonproto.MethodCheck(req.Method)
  157. if err != nil {
  158. c.Log("Error parsing request: ", string(daemonproto.Marshal(req)), err.Error())
  159. }
  160. handlerFunc, ok := router.Routes()[method]
  161. if !ok {
  162. err := InvalidAction{Msg: "Unimplemented method", Action: req.Method}
  163. c.Log("Error invoking the method: ", req.Method, "on the target: ", req.Target)
  164. return daemonproto.SockMessage{StatusMsg: daemonproto.UNRESOLVEABLE, Body: []byte(err.Error())}
  165. }
  166. return handlerFunc(req)
  167. }
  168. /*
  169. ###########################################
  170. ################ ERRORS ###################
  171. ###########################################
  172. */
  173. type InvalidAction struct {
  174. Msg string
  175. Action string
  176. }
  177. func (i *InvalidAction) Error() string {
  178. return fmt.Sprintf("Invalid action: '%s' parsed. Error: %s", i.Action, i.Msg)
  179. }
  180. type DaemonIoError struct {
  181. Msg []byte
  182. Action string
  183. }
  184. func (d *DaemonIoError) Error() string {
  185. return fmt.Sprintf("There was an error %s. Message: %s", d.Action, string(d.Msg))
  186. }