sock.go 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  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. /*
  50. ###############################
  51. ##### Protocol v2 methods #####
  52. ###############################
  53. */
  54. type Method string
  55. func MethodCheck(m string) (Method, error) {
  56. switch m {
  57. case "show":
  58. return SHOW, nil
  59. case "add":
  60. return ADD, nil
  61. case "delete":
  62. return DELETE, nil
  63. case "bootstrap":
  64. return BOOTSTRAP, nil
  65. case "reload":
  66. return RELOAD, nil
  67. case "poll":
  68. return POLL, nil
  69. case "run":
  70. return RUN, nil
  71. case "save":
  72. return SAVE, nil
  73. }
  74. return SHOW, &InvalidMethod{Method: m}
  75. }
  76. type InvalidMethod struct {
  77. Method string
  78. }
  79. func (i *InvalidMethod) Error() string {
  80. return "Invalid method passed: " + i.Method
  81. }
  82. const (
  83. SHOW Method = "show"
  84. ADD Method = "add"
  85. DELETE Method = "delete"
  86. BOOTSTRAP Method = "bootstrap"
  87. RELOAD Method = "reload"
  88. POLL Method = "poll"
  89. RUN Method = "run"
  90. SAVE Method = "save"
  91. )
  92. type SockMessage struct {
  93. Type string // the type of message being decoded
  94. TypeLen int8 // The length of the Type, used for convenience when Marshalling
  95. StatusMsg string // a string denoting what the output was, used in response messages
  96. StatusCode int8 // a status code that can be used to easily identify the type of error in response messages
  97. Version int8 `json:"version"` // This is a version header for failing fast
  98. Body []byte `json:"body"` // The body of a SockMessage SHOULD be json decodable, to allow for complex data to get sent over
  99. Target string `json:"target"` // This target 'route' for where this message should be sent. Think of this like an HTTP URI/path
  100. Method string `json:"method"` // This is the method that we will be executing on the target endpoint. Think of this like the HTTP method
  101. }
  102. func NewSockMessage(msgType string, statCode int8, body []byte) *SockMessage { // TODO: this function needs to be more versatile, and allow for additional more arguments
  103. return &SockMessage{Target: "",
  104. Method: "",
  105. Body: body,
  106. Version: SockMsgVers,
  107. Type: msgType,
  108. TypeLen: int8(len(msgType)),
  109. StatusCode: statCode,
  110. StatusMsg: RequestOk,
  111. }
  112. }
  113. /*
  114. Takes in a SockMessage struct and serializes it so that it can be sent over a socket, and then decoded as a SockMessage
  115. :param v: a SockMessage to serialize for transportation
  116. */
  117. 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
  118. msgHeader := []byte{}
  119. msgHeaderBuf := bytes.NewBuffer(msgHeader)
  120. preamble := []int8{
  121. SockMsgVers,
  122. v.StatusCode,
  123. v.TypeLen,
  124. }
  125. msgMeta := []int64{
  126. int64(len(v.Body)),
  127. int64(len(v.Target)),
  128. int64(len(v.Method)),
  129. }
  130. msgBody := [][]byte{
  131. []byte(v.Type),
  132. v.Body,
  133. []byte(v.Target),
  134. []byte(v.Method),
  135. }
  136. for i := range preamble {
  137. err := binary.Write(msgHeaderBuf, binary.LittleEndian, preamble[i])
  138. if err != nil {
  139. log.Fatal("Fatal error when writing: ", preamble[i], " into message header buffer.")
  140. }
  141. }
  142. for i := range msgMeta {
  143. err := binary.Write(msgHeaderBuf, binary.LittleEndian, msgMeta[i])
  144. if err != nil {
  145. log.Fatal("Fatal error when writing: ", msgMeta[i], " into message header buffer.")
  146. }
  147. }
  148. for i := range msgBody {
  149. _, err := msgHeaderBuf.Write(msgBody[i])
  150. if err != nil {
  151. log.Fatal("Fatal error when writing: ", msgBody[i], " into message header buffer.")
  152. }
  153. }
  154. return msgHeaderBuf.Bytes()
  155. }
  156. /*
  157. Unmarshalls a sock message byte array into a SockMessage struct, undoing what was done when Marshal() was called on the SockMessage
  158. :param msg: a byte array that can be unmarshalled into a SockMessage
  159. */
  160. func Unmarshal(msg []byte) SockMessage {
  161. vers := int8(msg[VersionIdx])
  162. statusCode := int8(msg[StatusCodeIdx])
  163. typeInfo := int(msg[TypeInfoIdx])
  164. bodyInfo := int(binary.LittleEndian.Uint64(msg[BodyInfoIdx:TargetInfoIdx]))
  165. targetInfo := int(binary.LittleEndian.Uint64(msg[TargetInfoIdx:MethodInfoIdx]))
  166. msgPayload := msg[MsgHeaderEnd:]
  167. body := msgPayload[typeInfo : typeInfo+bodyInfo]
  168. var msgInfo = []string{
  169. string(msgPayload[0:typeInfo]),
  170. string(msgPayload[(typeInfo + bodyInfo):(typeInfo + bodyInfo + targetInfo)]),
  171. string(msgPayload[(typeInfo + bodyInfo + targetInfo):]),
  172. }
  173. return SockMessage{
  174. Type: msgInfo[0],
  175. StatusCode: statusCode,
  176. StatusMsg: MESSAGE_RECIEVED,
  177. Version: vers,
  178. Body: body,
  179. Target: msgInfo[1],
  180. Method: msgInfo[2],
  181. }
  182. }
  183. type Context struct {
  184. conn net.Listener
  185. keyring *ApiKeyRing
  186. Keytags keytags.Keytagger
  187. routes map[string]Router
  188. sockPath string
  189. Config *Configuration
  190. servers []VpnServer
  191. rwBuffer bytes.Buffer
  192. stream io.Writer
  193. }
  194. /*
  195. Show all of the route information for the context
  196. :param msg: a message to parse from the daemon socket
  197. */
  198. func (c *Context) ShowRoutesHandler(msg SockMessage) SockMessage {
  199. var data string
  200. for k, v := range c.routes {
  201. data = data + k + "\n"
  202. routes := v.Routes()
  203. for i := range routes {
  204. data = data + "\u0009" + string(i) + "\n"
  205. }
  206. data = data + "\n"
  207. }
  208. return *NewSockMessage(MsgResponse, REQUEST_OK, []byte(data))
  209. }
  210. /*
  211. Context router
  212. */
  213. type ContextRouter struct {
  214. routes map[Method]func(SockMessage) SockMessage
  215. }
  216. func (c *ContextRouter) Register(method Method, callable func(SockMessage) SockMessage) {
  217. c.routes[method] = callable
  218. }
  219. func (c *ContextRouter) Routes() map[Method]func(SockMessage) SockMessage {
  220. return c.routes
  221. }
  222. func NewContextRouter() *ConfigRouter {
  223. return &ConfigRouter{routes: map[Method]func(SockMessage) SockMessage{}}
  224. }
  225. /*
  226. Write a message back to the caller
  227. */
  228. func (c *Context) Respond(conn net.Conn) {
  229. conn.Write(c.rwBuffer.Bytes())
  230. }
  231. /*
  232. Log wrapper for the context struct
  233. :param data: string arguments to send to the logger
  234. */
  235. func (c *Context) Log(msg ...string) {
  236. dMsg := []string{"daemon.Context:"}
  237. dMsg = append(dMsg, msg...)
  238. c.Config.Log(dMsg...)
  239. }
  240. func (c *Context) Handle(conn net.Conn) {
  241. defer conn.Close()
  242. b := make([]byte, 2048)
  243. nr, err := conn.Read(b)
  244. if err != nil {
  245. c.Log(err.Error())
  246. return
  247. }
  248. req := c.parseRequest(b[0:nr])
  249. out := c.resolveRoute(req)
  250. _, err = conn.Write(Marshal(out))
  251. if err != nil {
  252. c.Log(err.Error())
  253. return
  254. }
  255. }
  256. /*
  257. spawns subroutines to listen for different syscalls
  258. */
  259. func (c *Context) handleSyscalls() {
  260. // Cleanup the sockfile.
  261. chanSig := make(chan os.Signal, 1)
  262. signal.Notify(chanSig, os.Interrupt, syscall.SIGTERM)
  263. go func() {
  264. <-chanSig
  265. os.Remove(c.sockPath)
  266. os.Exit(1)
  267. }()
  268. }
  269. /*
  270. Open a daemon context pointer
  271. */
  272. func NewContext(path string, rdr io.Writer, apiKeyring *ApiKeyRing, conf *Configuration) *Context {
  273. sock, err := net.Listen("unix", path)
  274. if err != nil {
  275. log.Fatal(err)
  276. }
  277. routes := map[string]Router{}
  278. buf := make([]byte, 1024)
  279. return &Context{conn: sock, sockPath: path, rwBuffer: *bytes.NewBuffer(buf), stream: rdr, keyring: apiKeyring,
  280. routes: routes, Config: conf, Keytags: keytags.ConstKeytag{}}
  281. }
  282. /*
  283. Register a function to the daemons function router
  284. :param name: the name to map the function to. This will dictate how the CLI will resolve a keyword to the target function
  285. :param callable: the callable that will be executed when the keyword from 'name' is passed to the CLI
  286. */
  287. func (c *Context) Register(name string, router Router) {
  288. c.routes[name] = router
  289. }
  290. /*
  291. Hold the execution context open and listen for input
  292. */
  293. func (c *Context) ListenAndServe() {
  294. c.handleSyscalls()
  295. for {
  296. conn, err := c.conn.Accept()
  297. if err != nil {
  298. log.Fatal(err)
  299. }
  300. go c.Handle(conn)
  301. }
  302. }
  303. /*
  304. Validate and parse a stream from the unix socket and return an Action
  305. :param msg: a byte array with the action and arguments
  306. */
  307. func (c *Context) parseRequest(msg []byte) SockMessage {
  308. c.Log("Recieved request to parse action. ", string(msg))
  309. return Unmarshal(msg)
  310. }
  311. /*
  312. Resolve an action to a function
  313. :param action: a parsed action from the sock stream
  314. */
  315. func (c *Context) resolveRoute(req SockMessage) SockMessage {
  316. router, ok := c.routes[req.Target]
  317. if !ok {
  318. err := InvalidAction{Msg: "Invalid Action", Action: req.Target}
  319. c.Log("Error finding a router for target: ", req.Target)
  320. return SockMessage{StatusMsg: UNRESOLVEABLE, Body: []byte(err.Error())}
  321. }
  322. method, err := MethodCheck(req.Method)
  323. if err != nil {
  324. c.Log("Error parsing request: ", string(Marshal(req)), err.Error())
  325. }
  326. handlerFunc, ok := router.Routes()[method]
  327. if !ok {
  328. err := InvalidAction{Msg: "Unimplemented method", Action: req.Method}
  329. c.Log("Error invoking the method: ", req.Method, "on the target: ", req.Target)
  330. return SockMessage{StatusMsg: UNRESOLVEABLE, Body: []byte(err.Error())}
  331. }
  332. return handlerFunc(req)
  333. }
  334. /*
  335. ###########################################
  336. ################ ERRORS ###################
  337. ###########################################
  338. */
  339. type InvalidAction struct {
  340. Msg string
  341. Action string
  342. }
  343. func (i *InvalidAction) Error() string {
  344. return fmt.Sprintf("Invalid action: '%s' parsed. Error: %s", i.Action, i.Msg)
  345. }
  346. type DaemonIoError struct {
  347. Msg []byte
  348. Action string
  349. }
  350. func (d *DaemonIoError) Error() string {
  351. return fmt.Sprintf("There was an error %s. Message: %s", d.Action, string(d.Msg))
  352. }