sock.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. package daemon
  2. import (
  3. "bytes"
  4. _ "embed"
  5. "encoding/binary"
  6. "fmt"
  7. "io"
  8. "log"
  9. "net"
  10. "os"
  11. "os/signal"
  12. "syscall"
  13. "git.aetherial.dev/aeth/yosai/pkg/keytags"
  14. )
  15. /*
  16. #########################################################
  17. ######## PROTOCOL RELATED FUNCTIONS AND STRUCTS #########
  18. #########################################################
  19. */
  20. const SockMsgVers = 2
  21. const MESSAGE_RECIEVED = "MSG_RECV"
  22. const UNRESOLVEABLE = "UNRESOLVEABLE"
  23. const RequestOk = "OK"
  24. /*
  25. #################################
  26. ####### Protocol v2 area ########
  27. #################################
  28. */
  29. const VersionIdx = 0
  30. const StatusCodeIdx = 1
  31. const TypeInfoIdx = 2
  32. const BodyInfoIdx = 3
  33. const TargetInfoIdx = 11
  34. const MethodInfoIdx = 19
  35. const MsgHeaderEnd = 27
  36. const MsgRequest = "REQUEST"
  37. const MsgResponse = "RESPONSE"
  38. /*
  39. ################################
  40. ### Protocol v2 status codes ###
  41. ################################
  42. */
  43. const REQUEST_OK = 0
  44. const REQUEST_TIMEOUT = 1
  45. const REQUEST_FAILED = 2
  46. const REQUEST_UNAUTHORIZED = 3
  47. const REQUEST_ACCEPTED = 4
  48. const REQUEST_UNRESOLVED = 5
  49. type SockMessage struct {
  50. Type string // the type of message being decoded
  51. TypeLen int8 // The length of the Type, used for convenience when Marshalling
  52. StatusMsg string // a string denoting what the output was, used in response messages
  53. StatusCode int8 // a status code that can be used to easily identify the type of error in response messages
  54. Version int8 `json:"version"` // This is a version header for failing fast
  55. Body []byte `json:"body"` // The body of a SockMessage SHOULD be json decodable, to allow for complex data to get sent over
  56. Target string `json:"target"` // This target 'route' for where this message should be sent. Think of this like an HTTP URI/path
  57. Method string `json:"method"` // This is the method that we will be executing on the target endpoint. Think of this like the HTTP method
  58. }
  59. func NewSockMessage(msgType string, statCode int8, body []byte) *SockMessage { // TODO: this function needs to be more versatile, and allow for additional more arguments
  60. return &SockMessage{Target: "",
  61. Method: "",
  62. Body: body,
  63. Version: SockMsgVers,
  64. Type: msgType,
  65. TypeLen: int8(len(msgType)),
  66. StatusCode: statCode,
  67. StatusMsg: RequestOk,
  68. }
  69. }
  70. /*
  71. Takes in a SockMessage struct and serializes it so that it can be sent over a socket, and then decoded as a SockMessage
  72. :param v: a SockMessage to serialize for transportation
  73. */
  74. func Marshal(v SockMessage) []byte { // TODO: Need to clean up the error handling here. This is really brittle. I just wanted to get it working
  75. msgHeader := []byte{}
  76. msgHeaderBuf := bytes.NewBuffer(msgHeader)
  77. preamble := []int8{
  78. SockMsgVers,
  79. v.StatusCode,
  80. v.TypeLen,
  81. }
  82. msgMeta := []int64{
  83. int64(len(v.Body)),
  84. int64(len(v.Target)),
  85. int64(len(v.Method)),
  86. }
  87. msgBody := [][]byte{
  88. []byte(v.Type),
  89. v.Body,
  90. []byte(v.Target),
  91. []byte(v.Method),
  92. }
  93. for i := range preamble {
  94. err := binary.Write(msgHeaderBuf, binary.LittleEndian, preamble[i])
  95. if err != nil {
  96. log.Fatal("Fatal error when writing: ", preamble[i], " into message header buffer.")
  97. }
  98. }
  99. for i := range msgMeta {
  100. err := binary.Write(msgHeaderBuf, binary.LittleEndian, msgMeta[i])
  101. if err != nil {
  102. log.Fatal("Fatal error when writing: ", msgMeta[i], " into message header buffer.")
  103. }
  104. }
  105. for i := range msgBody {
  106. _, err := msgHeaderBuf.Write(msgBody[i])
  107. if err != nil {
  108. log.Fatal("Fatal error when writing: ", msgBody[i], " into message header buffer.")
  109. }
  110. }
  111. return msgHeaderBuf.Bytes()
  112. }
  113. /*
  114. Unmarshalls a sock message byte array into a SockMessage struct, undoing what was done when Marshal() was called on the SockMessage
  115. :param msg: a byte array that can be unmarshalled into a SockMessage
  116. */
  117. func Unmarshal(msg []byte) SockMessage {
  118. vers := int8(msg[VersionIdx])
  119. statusCode := int8(msg[StatusCodeIdx])
  120. typeInfo := int(msg[TypeInfoIdx])
  121. bodyInfo := int(binary.LittleEndian.Uint64(msg[BodyInfoIdx:TargetInfoIdx]))
  122. targetInfo := int(binary.LittleEndian.Uint64(msg[TargetInfoIdx:MethodInfoIdx]))
  123. msgPayload := msg[MsgHeaderEnd:]
  124. body := msgPayload[typeInfo : typeInfo+bodyInfo]
  125. var msgInfo = []string{
  126. string(msgPayload[0:typeInfo]),
  127. string(msgPayload[(typeInfo + bodyInfo):(typeInfo + bodyInfo + targetInfo)]),
  128. string(msgPayload[(typeInfo + bodyInfo + targetInfo):]),
  129. }
  130. return SockMessage{
  131. Type: msgInfo[0],
  132. StatusCode: statusCode,
  133. StatusMsg: MESSAGE_RECIEVED,
  134. Version: vers,
  135. Body: body,
  136. Target: msgInfo[1],
  137. Method: msgInfo[2],
  138. }
  139. }
  140. type Context struct {
  141. conn net.Listener
  142. keyring *ApiKeyRing
  143. Keytags keytags.Keytagger
  144. routes map[string]func(req SockMessage) SockMessage
  145. sockPath string
  146. Config *ConfigFromFile
  147. servers []VpnServer
  148. rwBuffer bytes.Buffer
  149. stream io.Writer
  150. }
  151. /*
  152. Write a message back to the caller
  153. */
  154. func (c *Context) Respond(conn net.Conn) {
  155. conn.Write(c.rwBuffer.Bytes())
  156. }
  157. /*
  158. Log wrapper for the context struct
  159. :param data: string arguments to send to the logger
  160. */
  161. func (c *Context) Log(msg ...string) {
  162. dMsg := []string{"daemon.Context:"}
  163. dMsg = append(dMsg, msg...)
  164. c.Config.Log(dMsg...)
  165. }
  166. func (c *Context) Handle(conn net.Conn) {
  167. defer conn.Close()
  168. b := make([]byte, 2048)
  169. nr, err := conn.Read(b)
  170. if err != nil {
  171. c.Log(err.Error())
  172. return
  173. }
  174. req := c.parseRequest(b[0:nr])
  175. out := c.resolveRoute(req)
  176. _, err = conn.Write(Marshal(out))
  177. if err != nil {
  178. c.Log(err.Error())
  179. return
  180. }
  181. }
  182. /*
  183. spawns subroutines to listen for different syscalls
  184. */
  185. func (c *Context) handleSyscalls() {
  186. // Cleanup the sockfile.
  187. chanSig := make(chan os.Signal, 1)
  188. signal.Notify(chanSig, os.Interrupt, syscall.SIGTERM)
  189. go func() {
  190. <-chanSig
  191. os.Remove(c.sockPath)
  192. os.Exit(1)
  193. }()
  194. }
  195. /*
  196. Open a daemon context pointer
  197. */
  198. func NewContext(path string, rdr io.Writer, apiKeyring *ApiKeyRing, conf *ConfigFromFile) *Context {
  199. sock, err := net.Listen("unix", path)
  200. if err != nil {
  201. log.Fatal(err)
  202. }
  203. routes := map[string]func(req SockMessage) SockMessage{}
  204. buf := make([]byte, 1024)
  205. return &Context{conn: sock, sockPath: path, rwBuffer: *bytes.NewBuffer(buf), stream: rdr, keyring: apiKeyring,
  206. routes: routes, Config: conf, Keytags: keytags.ConstKeytag{}}
  207. }
  208. /*
  209. Register a function to the daemons function router
  210. :param name: the name to map the function to. This will dictate how the CLI will resolve a keyword to the target function
  211. :param callable: the callable that will be executed when the keyword from 'name' is passed to the CLI
  212. */
  213. func (c *Context) Register(name string, callable func(req SockMessage) SockMessage) {
  214. c.routes[name] = callable
  215. }
  216. /*
  217. Hold the execution context open and listen for input
  218. */
  219. func (c *Context) ListenAndServe() {
  220. c.handleSyscalls()
  221. for {
  222. conn, err := c.conn.Accept()
  223. if err != nil {
  224. log.Fatal(err)
  225. }
  226. go c.Handle(conn)
  227. }
  228. }
  229. /*
  230. Validate and parse a stream from the unix socket and return an Action
  231. :param msg: a byte array with the action and arguments
  232. */
  233. func (c *Context) parseRequest(msg []byte) SockMessage {
  234. c.Log("Recieved request to parse action. ", string(msg))
  235. return Unmarshal(msg)
  236. }
  237. /*
  238. Resolve an action to a function
  239. :param action: a parsed action from the sock stream
  240. */
  241. func (c *Context) resolveRoute(req SockMessage) SockMessage {
  242. handlerFunc, ok := c.routes[req.Target]
  243. if !ok {
  244. err := &InvalidAction{Msg: "Invalid Action", Action: req.Target}
  245. return SockMessage{StatusMsg: UNRESOLVEABLE, Body: []byte(err.Error())}
  246. }
  247. return handlerFunc(req)
  248. }
  249. /*
  250. ###########################################
  251. ################ ERRORS ###################
  252. ###########################################
  253. */
  254. type InvalidAction struct {
  255. Msg string
  256. Action string
  257. }
  258. func (i *InvalidAction) Error() string {
  259. return fmt.Sprintf("Invalid action: '%s' parsed. Error: %s", i.Action, i.Msg)
  260. }
  261. type DaemonIoError struct {
  262. Msg []byte
  263. Action string
  264. }
  265. func (d *DaemonIoError) Error() string {
  266. return fmt.Sprintf("There was an error %s. Message: %s", d.Action, string(d.Msg))
  267. }