ffpb.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. # 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. self.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,self.data))
  33. class ThreadingTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
  34. pass
  35. def setup(bot):
  36. host = "localhost"
  37. port = 4342
  38. if not bot.config.ffpb.msg_host is None: host = bot.config.ffpb.msg_host
  39. if not bot.config.ffpb.msg_port is None: port = int(bot.config.ffpb.msg_port)
  40. msgserver = ThreadingTCPServer((host,port), MsgHandler)
  41. msgserver.bot = bot
  42. ip, port = msgserver.server_address
  43. print("Messaging server listening on {}:{}".format(ip,port))
  44. msgserver_thread = threading.Thread(target=msgserver.serve_forever)
  45. msgserver_thread.daemon = True
  46. msgserver_thread.start()
  47. @willie.module.commands('status')
  48. def ffpb_status(bot, trigger):
  49. """Status des FFPB-Netzes: Anzahl (aktiver) Knoten + Clients"""
  50. response = urllib2.urlopen('http://nodecount.paderborn.freifunk.net/')
  51. html = response.read()
  52. m = re.search('<div id="nodecount">\s*(\d+)\s*</div>', html)
  53. nodecount = int(m.group(1))
  54. bot.say('nodecount = {}'.format(nodecount))
  55. def ffpb_get_address(name):
  56. peerfilename = '/home/ffpb-statusbot/knoten/' + name
  57. peer_mac = None
  58. if os.path.exists(peerfilename):
  59. peerfile = open(peerfilename, "r")
  60. for line in peerfile:
  61. if line.startswith("# MAC:"):
  62. peer_mac = line[6:].strip()
  63. peerfile.close()
  64. print("peer '", name, "': file '", peerfilename, "', MAC ", peer_mac, sep='')
  65. if not (peer_mac is None):
  66. return str(netaddr.EUI(peer_mac).ipv6_link_local())
  67. return None
  68. @willie.module.commands('ping')
  69. def ffpb_ping(bot, trigger):
  70. """Ping FFPB-Knoten"""
  71. target_name = trigger.group(2)
  72. if target_name is None or len(target_name) == 0:
  73. bot.say('Alter, wen soll ich denn pingen? Einmal mit Profis arbeiten -.-')
  74. return
  75. target = ffpb_get_address(target_name)
  76. if target is None:
  77. bot.say('Kein Plan wer mit \'' + target_name + '\' gemeint ist :/')
  78. return
  79. if target.startswith('fe80::'):
  80. target = 'fdca:ffee:ff12:132:' + target[6:]
  81. print("ping '", target , '"', sep='')
  82. result = os.system('ping6 -c 1 -W 2 ' + target + ' 2>/dev/null')
  83. if result == 0:
  84. bot.say('Knoten "' + target_name + '" antwortet \o/')
  85. elif result == 1 or result == 256:
  86. bot.say('Keine Antwort von "' + target_name + '" :-(')
  87. else:
  88. bot.say('Uh oh, irgendwas ist kaputt. Chef, ping result = ' + str(result) + ' - darf ich das essen?')
  89. @willie.module.commands('exec-on-peer')
  90. def ffpb_remoteexec(bot, trigger):
  91. """Remote Execution fuer FFPB_Knoten"""
  92. bot_params = trigger.group(2).split(' ',1)
  93. if len(bot_params) != 2:
  94. bot.say('Wenn du nicht sagst wo mach ich remote execution bei dir!')
  95. bot.say('Tipp: !exec-on-peer <peer> <cmd>')
  96. return
  97. target_name = bot_params[0]
  98. target_cmd = bot_params[1]
  99. if not trigger.admin:
  100. bot.say('Captcha required: https://xkcd.com/565/')
  101. return
  102. target = ffpb_get_address(target_name)
  103. if target is None:
  104. bot.say('Kein Plan wer mit \'' + target_name + '\' gemeint ist :/')
  105. if target.startswith('fe80::'):
  106. target = 'fdca:ffee:ff12:132:' + target[6:]
  107. cmd = 'ssh -6 -l root ' + target + ' -- "' + target_cmd + '"'
  108. print("REMOTE EXEC = " + cmd)
  109. try:
  110. result = subprocess.check_output(['ssh', '-6n', '-l', 'root', '-o', 'BatchMode=yes', '-o','StrictHostKeyChecking=no', target, target_cmd], stderr=subprocess.STDOUT, shell=False)
  111. lines = str(result).splitlines()
  112. bot.say('exec-on-peer(' + target_name + '): ' + str(len(lines)) + ' Zeilen (zeige max. 8):')
  113. for line in lines[0:8]:
  114. bot.say(line)
  115. except subprocess.CalledProcessError, e:
  116. bot.say('Fehler '+str(e.returncode)+' bei exec-on-peer('+target_name+'): ' + e.output)