ffpb.py 4.9 KB

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