ffpb.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import willie
  2. import netaddr
  3. import urllib3
  4. import re
  5. import os
  6. import subprocess
  7. import socket
  8. import socketserver
  9. import threading
  10. msgserver = None
  11. # TODO: move into config file :)
  12. msgserver_known_senders = {
  13. "127.0.0.1": "localhost",
  14. "10.132.254.1": "gw01",
  15. "10.132.254.2": "gw02",
  16. "10.132.254.3": "gw03",
  17. "10.132.254.80": "public"
  18. }
  19. class MsgHandler(socketserver.BaseRequestHandler):
  20. def handle(self):
  21. data = self.request.recv(2048).strip()
  22. sender = self.client_address[0]
  23. if sender in msgserver_known_senders:
  24. sender = msgserver_known_senders[sender]
  25. bot = self.server.bot
  26. if bot is None:
  27. print("ERROR: No bot in handle() :-(")
  28. return
  29. target = bot.config.core.owner
  30. if bot.config.has_section('ffpb') and not (bot.config.ffpb.msg_target is None):
  31. target = bot.config.ffpb.msg_target
  32. bot.msg(target, "[{0}] {1}".format(sender,str(data, "utf-8")))
  33. class ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
  34. pass
  35. def setup(bot):
  36. global msgserver
  37. if bot.config.has_section('ffpb') and int(bot.config.ffpb.msg_enable) == 1:
  38. host = "localhost"
  39. port = 2342
  40. if not bot.config.ffpb.msg_host is None: host = bot.config.ffpb.msg_host
  41. if not bot.config.ffpb.msg_port is None: port = int(bot.config.ffpb.msg_port)
  42. msgserver = ThreadingTCPServer((host,port), MsgHandler)
  43. msgserver.bot = bot
  44. ip, port = msgserver.server_address
  45. print("Messaging server listening on {}:{}".format(ip,port))
  46. msgserver_thread = threading.Thread(target=msgserver.serve_forever)
  47. msgserver_thread.daemon = True
  48. msgserver_thread.start()
  49. def shutdown(bot):
  50. global msgserver
  51. if not msgserver is None:
  52. msgserver.shutdown()
  53. print("Closed messaging server.")
  54. msgserver = None
  55. @willie.module.commands('status')
  56. def ffpb_status(bot, trigger):
  57. """Status des FFPB-Netzes: Anzahl (aktiver) Knoten + Clients"""
  58. response = urllib3.urlopen('http://nodecount.paderborn.freifunk.net/')
  59. html = response.read()
  60. m = re.search('<div id="nodecount">\s*(\d+)\s*</div>', html)
  61. nodecount = int(m.group(1))
  62. bot.say('nodecount = {}'.format(nodecount))
  63. def ffpb_get_address(name):
  64. peerfilename = '/home/ffpb-statusbot/knoten/' + name
  65. peer_mac = None
  66. if os.path.exists(peerfilename):
  67. peerfile = open(peerfilename, "r")
  68. for line in peerfile:
  69. if line.startswith("# MAC:"):
  70. peer_mac = line[6:].strip()
  71. peerfile.close()
  72. print("peer '", name, "': file '", peerfilename, "', MAC ", peer_mac, sep='')
  73. if not (peer_mac is None):
  74. return str(netaddr.EUI(peer_mac).ipv6_link_local())
  75. return None
  76. @willie.module.commands('ping')
  77. def ffpb_ping(bot, trigger):
  78. """Ping FFPB-Knoten"""
  79. target_name = trigger.group(2)
  80. if target_name is None or len(target_name) == 0:
  81. bot.say('Alter, wen soll ich denn pingen? Einmal mit Profis arbeiten -.-')
  82. return
  83. target = ffpb_get_address(target_name)
  84. if target is None:
  85. bot.say('Kein Plan wer mit \'' + target_name + '\' gemeint ist :/')
  86. return
  87. if target.startswith('fe80::'):
  88. target = 'fdca:ffee:ff12:132:' + target[6:]
  89. print("ping '", target , '"', sep='')
  90. result = os.system('ping6 -c 1 -W 2 ' + target + ' 2>/dev/null')
  91. if result == 0:
  92. bot.say('Knoten "' + target_name + '" antwortet \o/')
  93. elif result == 1 or result == 256:
  94. bot.say('Keine Antwort von "' + target_name + '" :-(')
  95. else:
  96. bot.say('Uh oh, irgendwas ist kaputt. Chef, ping result = ' + str(result) + ' - darf ich das essen?')
  97. @willie.module.commands('exec-on-peer')
  98. def ffpb_remoteexec(bot, trigger):
  99. """Remote Execution fuer FFPB_Knoten"""
  100. bot_params = trigger.group(2).split(' ',1)
  101. if len(bot_params) != 2:
  102. bot.say('Wenn du nicht sagst wo mach ich remote execution bei dir!')
  103. bot.say('Tipp: !exec-on-peer <peer> <cmd>')
  104. return
  105. target_name = bot_params[0]
  106. target_cmd = bot_params[1]
  107. if not trigger.admin:
  108. bot.say('I can haz sudo?')
  109. return
  110. if trigger.is_privmsg:
  111. bot.say('Bitte per Channel.')
  112. return
  113. if not trigger.nick in bot.ops[trigger.sender]:
  114. bot.say('Geh weg.')
  115. return
  116. target = ffpb_get_address(target_name)
  117. if target is None:
  118. bot.say('Kein Plan wer mit \'' + target_name + '\' gemeint ist :/')
  119. return
  120. if target.startswith('fe80::'):
  121. target = 'fdca:ffee:ff12:132:' + target[6:]
  122. cmd = 'ssh -6 -l root ' + target + ' -- "' + target_cmd + '"'
  123. print("REMOTE EXEC = " + cmd)
  124. try:
  125. result = subprocess.check_output(['ssh', '-6n', '-l', 'root', '-o', 'BatchMode=yes', '-o','StrictHostKeyChecking=no', target, target_cmd], stderr=subprocess.STDOUT, shell=False)
  126. lines = str(result).splitlines()
  127. if len(lines) == 0:
  128. bot.say('exec-on-peer(' + target_name + '): No output')
  129. return
  130. msg = 'exec-on-peer(' + target_name + '): ' + str(len(lines)) + ' Zeilen'
  131. if len(lines) > 8:
  132. msg += ' (zeige max. 8)'
  133. bot.say(msg + ':')
  134. for line in lines[0:8]:
  135. bot.say(line)
  136. except subprocess.CalledProcessError as e:
  137. bot.say('Fehler '+str(e.returncode)+' bei exec-on-peer('+target_name+'): ' + e.output)