pmanager.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #!/usr/bin/env python3
  2. import json
  3. import os
  4. import signal
  5. import socket
  6. import subprocess
  7. import sys
  8. import time
  9. import websocket
  10. DEBUG = True
  11. DEBUG = False
  12. def log(s):
  13. if not DEBUG:
  14. return
  15. print(s)
  16. def sendmsg(msg):
  17. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  18. ret = None
  19. try:
  20. s.connect(('localhost', 9999))
  21. tosend = msg + "\r\n"
  22. encoded_msg = tosend.encode("ascii")
  23. s.sendall(encoded_msg)
  24. ret = s.recv(4096)
  25. s.close()
  26. except Exception as e:
  27. log(e)
  28. return None
  29. log("[nc output] %s " % ret)
  30. return ret
  31. class PManager:
  32. ws = websocket.WebSocket()
  33. ip = "ws://192.168.1.208:9001"
  34. p_list = {}
  35. ptable = {}
  36. log_list = {}
  37. name = ""
  38. def __init__(self, name, ptable):
  39. self.ptable = ptable
  40. self.conn(self.ip)
  41. self.name = name
  42. signal.signal(signal.SIGINT, self.sighandler)
  43. signal.signal(signal.SIGCHLD, signal.SIG_IGN) #To kill zombies
  44. while True:
  45. try:
  46. data = self.ws.recv()
  47. except Exception as e:
  48. log(e)
  49. self.conn(self.ip)
  50. continue
  51. try:
  52. j = json.loads(data)
  53. except Exception as e:
  54. log(e)
  55. log("Invalid json?")
  56. continue
  57. if ("type" not in j or "command" not in j or
  58. "key" not in j or j["type"] != "snowmix"):
  59. log("Dropping: %s" % j)
  60. continue
  61. #log(j)
  62. if j["command"] == "oneshot":
  63. self.oneshot(j["key"])
  64. if j["command"] == "launch":
  65. opts = None
  66. if "options" in j:
  67. opts = j["options"]
  68. self.launch(j["key"],opts)
  69. if j["command"] == "kill":
  70. self.stop(j["key"])
  71. if j["command"] == "netcat":
  72. sendmsg(j["key"])
  73. if j["command"] == "status": #and j["key"] == self.name:
  74. self.send({"type": "snowmix", "type": "statusreport", "name": self.name, "data":self.p_list})
  75. def send(self, data):
  76. try:
  77. if type(data) is dict:
  78. data = json.dumps(data)
  79. print(data)
  80. self.ws.send(data)
  81. except Exception as e:
  82. print(e)
  83. def conn(self, target):
  84. if self.ws is None:
  85. self.ws = websocket.WebSocket()
  86. try:
  87. self.ws.connect(target)
  88. except Exception as e:
  89. log(e)
  90. time.sleep(2)
  91. self.conn(target) #keep trying you basterd
  92. def close(self):
  93. if self.ws is None:
  94. return
  95. self.ws.close()
  96. def sighandler(self, sig, frame):
  97. log("\rExiting!")
  98. self.close()
  99. log("Bye!")
  100. sys.exit(0)
  101. def stop(self, key):
  102. if key not in self.p_list:
  103. log("key %s doesn't exist! not killing!" % (key))
  104. return
  105. try:
  106. os.killpg(os.getpgid(self.p_list[key]), signal.SIGTERM)
  107. except Exception as e:
  108. log("This process (%d) can't be killed! Why?" % self.p_list[key])
  109. log(e)
  110. try:
  111. self.log_list[key].close()
  112. except Exception as e:
  113. log("ex file: %s" % e)
  114. if key in self.log_list:
  115. del self.log_list[key]
  116. del self.p_list[key]
  117. def oneshot(self, key):
  118. if key not in self.ptable:
  119. log("This process (%s) is not on my table!" % key)
  120. return
  121. log("Oneshotting! key: %s" % key)
  122. try:
  123. proc = subprocess.Popen(self.ptable[key], preexec_fn=os.setsid)
  124. except Exception as e:
  125. log(e)
  126. def launch(self, key, options=None):
  127. if key in self.p_list:
  128. log("key %s exist! not running!" % (key))
  129. return
  130. if key not in self.ptable:
  131. log("This process (%s) is not on my table!" % key)
  132. return
  133. log("Launching! key: %s, opts: %s" % (key, options))
  134. tolaunch = self.ptable[key]
  135. if options is not None:
  136. options = [ o for o in options if type(o) is str ]
  137. tolaunch = tolaunch + options
  138. log(tolaunch)
  139. self.log_list[key] = open("/tmp/%s" % key, "w")
  140. try:
  141. proc = subprocess.Popen(tolaunch, preexec_fn=os.setsid, stdout=self.log_list[key])
  142. #Le doy su propio grupo al subproceso
  143. except Exception as e:
  144. log(e)
  145. sys.exit(1)
  146. self.p_list[key] = proc.pid
  147. return proc.pid
  148. if __name__ == "__main__":
  149. if len(sys.argv) != 2:
  150. print("Usage: ./%s <file.json>" % (sys.argv[0]))
  151. sys.exit(1)
  152. try:
  153. data = json.loads(open(sys.argv[1]).read())
  154. except Exception as e:
  155. print(e)
  156. sys.exit(2)
  157. ptable = data["data"]
  158. name = data["name"]
  159. m = PManager(name, ptable)