ffpb.py 5.2 KB

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