Skip to content
Snippets Groups Projects
Commit 63adccf6 authored by Marcus Scharf's avatar Marcus Scharf
Browse files

style rework / fix bug / default-config rework

parent 7743853c
No related branches found
No related tags found
No related merge requests found
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
"latitude": 89.10727755551, "latitude": 89.10727755551,
"longitude": 5.00932562351 "longitude": 5.00932562351
}, },
"vpn": true,
"pages": [ "pages": [
"http://start.ffggrz/", "http://start.ffggrz/",
"http://start.ffggrz.de/" "http://start.ffggrz.de/"
......
...@@ -4,8 +4,8 @@ import json ...@@ -4,8 +4,8 @@ import json
import argparse import argparse
import sys import sys
from lib.respondd_client import ResponddClient from lib.respondd_client import ResponddClient
import lib.helper
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
...@@ -16,12 +16,18 @@ parser.add_argument('-t', '--dry-run', action='store_true', help='Dry Run', requ ...@@ -16,12 +16,18 @@ parser.add_argument('-t', '--dry-run', action='store_true', help='Dry Run', requ
args = parser.parse_args() args = parser.parse_args()
options = vars(args) options = vars(args)
config = {} config = {
'bridge': 'br-client',
'batman': 'bat0',
'port': 1001,
'addr': 'ff02::2:1001'
}
try: try:
with open("config.json", 'r') as fh: with open("config.json", 'r') as fh:
config = json.load(fh) config = lib.helper.merge(config, json.load(fh))
except IOError: except IOError:
raise print('no config.json, use defaults')
if options["test"]: if options["test"]:
from lib.nodeinfo import Nodeinfo from lib.nodeinfo import Nodeinfo
...@@ -32,8 +38,8 @@ if options["test"]: ...@@ -32,8 +38,8 @@ if options["test"]:
print(json.dumps(Neighbours(config).getStruct(), sort_keys=True, indent=4)) print(json.dumps(Neighbours(config).getStruct(), sort_keys=True, indent=4))
sys.exit(1) sys.exit(1)
config["verbose"] = options["verbose"] config['verbose'] = options['verbose']
config["dry_run"] = options["dry_run"] config['dry_run'] = options['dry_run']
extResponddClient = ResponddClient(config) extResponddClient = ResponddClient(config)
extResponddClient.start() extResponddClient.start()
......
...@@ -2,15 +2,20 @@ ...@@ -2,15 +2,20 @@
import netifaces as netif import netifaces as netif
import subprocess import subprocess
import sys
def toUTF8(line):
return line.decode("utf-8")
def call(cmdnargs): def call(cmdnargs):
output = subprocess.check_output(cmdnargs) try:
output = subprocess.check_output(cmdnargs, stderr=subprocess.STDOUT)
lines = output.splitlines() lines = output.splitlines()
lines = [toUTF8(line) for line in lines] lines = [line.decode('utf-8') for line in lines]
return lines return lines
except subprocess.CalledProcessError as err:
print(err)
return []
except:
print(str(sys.exc_info()[0]))
return []
def merge(a, b): def merge(a, b):
if isinstance(a, dict) and isinstance(b, dict): if isinstance(a, dict) and isinstance(b, dict):
...@@ -23,10 +28,11 @@ def merge(a, b): ...@@ -23,10 +28,11 @@ def merge(a, b):
return a if b is None else b return a if b is None else b
def getDevice_MAC(dev): def getInterfaceMAC(interface):
try: try:
interface = netif.ifaddresses(dev) interface = netif.ifaddresses(interface)
mac = interface[netif.AF_LINK] mac = interface[netif.AF_LINK]
return mac[0]['addr'] return mac[0]['addr']
except: except:
return None return None
#!/usr/bin/env python3 #!/usr/bin/env python3
import subprocess
import re import re
from lib.respondd import Respondd from lib.respondd import Respondd
...@@ -11,92 +10,82 @@ class Neighbours(Respondd): ...@@ -11,92 +10,82 @@ class Neighbours(Respondd):
def __init__(self, config): def __init__(self, config):
Respondd.__init__(self, config) Respondd.__init__(self, config)
def getStationDump(self, devList): @staticmethod
j = {} def getStationDump(interfaceList):
ret = {}
for dev in devList: for interface in interfaceList:
try: mac = ''
output = subprocess.check_output(["iw", "dev", dev, "station", "dump"]) lines = lib.helper.call(['iw', 'dev', interface, 'station', 'dump'])
output_utf8 = output.decode("utf-8")
lines = output_utf8.splitlines()
mac = ""
for line in lines: for line in lines:
# Station 32:b8:c3:86:3e:e8 (on ibss3) # Station 32:b8:c3:86:3e:e8 (on ibss3)
ml = re.match(r"^Station ([0-9a-f:]+) \(on ([\w\d]+)\)", line, re.I) lineMatch = re.match(r'^Station ([0-9a-f:]+) \(on ([\w\d]+)\)', line, re.I)
if ml: if lineMatch:
mac = ml.group(1) mac = lineMatch.group(1)
j[mac] = {} ret[mac] = {}
else: else:
ml = re.match(r"^[\t ]+([^:]+):[\t ]+([^ ]+)", line, re.I) lineMatch = re.match(r'^[\t ]+([^:]+):[\t ]+([^ ]+)', line, re.I)
if ml: if lineMatch:
j[mac][ ml.group(1) ] = ml.group(2) ret[mac][lineMatch.group(1)] = lineMatch.group(2)
except: return ret
pass
return j
def getMeshInterfaces(self, batmanDev):
j = {}
output = subprocess.check_output(["batctl", "-m", batmanDev, "if"]) @staticmethod
output_utf8 = output.decode("utf-8") def getMeshInterfaces(batmanInterface):
lines = output_utf8.splitlines() ret = {}
lines = lib.helper.call(['batctl', '-m', batmanInterface, 'if'])
for line in lines: for line in lines:
ml = re.match(r"^([^:]*)", line) lineMatch = re.match(r'^([^:]*)', line)
dev = ml.group(1) interface = lineMatch.group(1)
j[dev] = lib.helper.getDevice_MAC(dev) ret[interface] = lib.helper.getInterfaceMAC(interface)
return j return ret
def _get(self): def _get(self):
j = {"batadv": {}} ret = {'batadv': {}}
stationDump = None stationDump = None
if 'mesh-wlan' in self._config: if 'mesh-wlan' in self._config:
j["wifi"] = {} ret['wifi'] = {}
stationDump = self.getStationDump(self._config["mesh-wlan"]) stationDump = self.getStationDump(self._config['mesh-wlan'])
meshInterfaces = self.getMeshInterfaces(self._config['batman']) meshInterfaces = self.getMeshInterfaces(self._config['batman'])
output = subprocess.check_output(["batctl", "-m", self._config['batman'], "o", "-n"]) lines = lib.helper.call(['batctl', '-m', self._config['batman'], 'o', '-n'])
output_utf8 = output.decode("utf-8")
lines = output_utf8.splitlines()
for line in lines: for line in lines:
# * e2:ad:db:b7:66:63 2.712s (175) be:b7:25:4f:8f:96 [mesh-vpn-l2tp-1] # * e2:ad:db:b7:66:63 2.712s (175) be:b7:25:4f:8f:96 [mesh-vpn-l2tp-1]
ml = re.match(r"^[ \*\t]*([0-9a-f:]+)[ ]*([\d\.]*)s[ ]*\(([ ]*\d*)\)[ ]*([0-9a-f:]+)[ ]*\[[ ]*(.*)\]", line, re.I) lineMatch = re.match(r'^[ \*\t]*([0-9a-f:]+)[ ]*([\d\.]*)s[ ]*\(([ ]*\d*)\)[ ]*([0-9a-f:]+)[ ]*\[[ ]*(.*)\]', line, re.I)
if ml: if lineMatch:
dev = ml.group(5) interface = lineMatch.group(5)
macOrigin = ml.group(1) macOrigin = lineMatch.group(1)
macNexthop = ml.group(4) macNexthop = lineMatch.group(4)
tq = ml.group(3) tq = lineMatch.group(3)
lastseen = ml.group(2) lastseen = lineMatch.group(2)
if macOrigin == macNexthop: if macOrigin == macNexthop:
if 'mesh-wlan' in self._config and dev in self._config["mesh-wlan"] and not stationDump is None: if 'mesh-wlan' in self._config and interface in self._config['mesh-wlan'] and stationDump is not None:
if not meshInterfaces[dev] in j["wifi"]: if meshInterfaces[interface] not in ret['wifi']:
j["wifi"][ meshInterfaces[dev] ] = {} ret['wifi'][meshInterfaces[interface]] = {}
j["wifi"][ meshInterfaces[dev] ]["neighbours"] = {} ret['wifi'][meshInterfaces[interface]]['neighbours'] = {}
if macOrigin in stationDump: if macOrigin in stationDump:
j["wifi"][ meshInterfaces[dev] ]["neighbours"][macOrigin] = { ret['wifi'][meshInterfaces[interface]]['neighbours'][macOrigin] = {
"signal": stationDump[macOrigin]["signal"], 'signal': stationDump[macOrigin]['signal'],
"noise": 0, # TODO: fehlt noch 'noise': 0, # TODO: fehlt noch
"inactive": stationDump[macOrigin]["inactive time"] 'inactive': stationDump[macOrigin]['inactive time']
} }
if dev in meshInterfaces: if interface in meshInterfaces:
if not meshInterfaces[dev] in j["batadv"]: if meshInterfaces[interface] not in ret['batadv']:
j["batadv"][ meshInterfaces[dev] ] = {} ret['batadv'][meshInterfaces[interface]] = {}
j["batadv"][ meshInterfaces[dev] ]["neighbours"] = {} ret['batadv'][meshInterfaces[interface]]['neighbours'] = {}
j["batadv"][ meshInterfaces[dev] ]["neighbours"][macOrigin] = { ret['batadv'][meshInterfaces[interface]]['neighbours'][macOrigin] = {
"tq": int(tq), 'tq': int(tq),
"lastseen": float(lastseen) 'lastseen': float(lastseen)
} }
return j return ret
#!/usr/bin/env python3 #!/usr/bin/env python3
import socket import socket
import netifaces as netif
import subprocess
import re import re
import netifaces as netif
from lib.respondd import Respondd from lib.respondd import Respondd
import lib.helper import lib.helper
...@@ -13,116 +12,120 @@ class Nodeinfo(Respondd): ...@@ -13,116 +12,120 @@ class Nodeinfo(Respondd):
def __init__(self, config): def __init__(self, config):
Respondd.__init__(self, config) Respondd.__init__(self, config)
def getDeviceAddresses(self, dev): @staticmethod
l = [] def getInterfaceAddresses(interface):
addresses = []
try: try:
for ip6 in netif.ifaddresses(dev)[netif.AF_INET6]: for ip6 in netif.ifaddresses(interface)[netif.AF_INET6]:
raw6 = ip6['addr'].split('%') addresses.append(ip6['addr'].split('%')[0])
l.append(raw6[0])
for ip in netif.ifaddresses(dev)[netif.AF_INET]: for ip in netif.ifaddresses(interface)[netif.AF_INET]:
raw = ip['addr'].split('%') addresses.append(ip['addr'].split('%')[0])
l.append(raw[0])
except: except:
pass pass
return l return addresses
def getBatmanInterfaces(self, dev):
j = {}
output = subprocess.check_output(["batctl", "-m", dev, "if"]) def getBatmanInterfaces(self, batmanInterface):
output_utf8 = output.decode("utf-8") ret = {}
lines = output_utf8.splitlines()
lines = lib.helper.call(['batctl', '-m', batmanInterface, 'if'])
for line in lines: for line in lines:
dev_line = re.match(r"^([^:]*)", line) lineMatch = re.match(r'^([^:]*)', line)
nif = dev_line.group(0) interface = lineMatch.group(0)
if_group = "" interfaceType = ''
if "fastd" in self._config and nif == self._config["fastd"]: # keep for compatibility if 'fastd' in self._config and interface == self._config['fastd']: # keep for compatibility
if_group = "tunnel" interfaceType = 'tunnel'
elif nif.find("l2tp") != -1: elif interface.find('l2tp') != -1:
if_group = "l2tp" interfaceType = 'l2tp'
elif "mesh-vpn" in self._config and nif in self._config["mesh-vpn"]: elif 'mesh-vpn' in self._config and interface in self._config['mesh-vpn']:
if_group = "tunnel" interfaceType = 'tunnel'
elif "mesh-wlan" in self._config and nif in self._config["mesh-wlan"]: elif 'mesh-wlan' in self._config and interface in self._config['mesh-wlan']:
if_group = "wireless" interfaceType = 'wireless'
else: else:
if_group = "other" interfaceType = 'other'
if not if_group in j: if interfaceType not in ret:
j[if_group] = [] ret[interfaceType] = []
j[if_group].append(lib.helper.getDevice_MAC(nif)) ret[interfaceType].append(lib.helper.getInterfaceMAC(interface))
if "l2tp" in j: if 'l2tp' in ret:
if "tunnel" in j: if 'tunnel' in ret:
j["tunnel"] = j["tunnel"] + j["l2tp"] ret['tunnel'] += ret['l2tp']
else: else:
j["tunnel"] = j["l2tp"] ret['tunnel'] = ret['l2tp']
return j return ret
def getCPUInfo(self): @staticmethod
j = {} def getCPUInfo():
ret = {}
with open("/proc/cpuinfo", 'r') as fh: with open('/proc/cpuinfo', 'r') as fh:
for line in fh: for line in fh:
ml = re.match(r"^(.+?)[\t ]+:[\t ]+(.*)$", line, re.I) lineMatch = re.match(r'^(.+?)[\t ]+:[\t ]+(.*)$', line, re.I)
if lineMatch:
ret[lineMatch.group(1)] = lineMatch.group(2)
if ml: return ret
j[ml.group(1)] = ml.group(2)
return j @staticmethod
def getVPN(batmanInterface):
lines = lib.helper.call(['batctl', '-m', batmanInterface, 'gw_mode'])
if re.match(r'^server', lines[0]):
return True
else:
return False
def _get(self): def _get(self):
j = { ret = {
"hostname": socket.gethostname(), 'hostname': socket.gethostname(),
"network": { 'network': {
"addresses": self.getDeviceAddresses(self._config['bridge']), 'addresses': self.getInterfaceAddresses(self._config['bridge']),
"mesh": { 'mesh': {
"bat0": { 'bat0': {
"interfaces": self.getBatmanInterfaces(self._config['batman']) 'interfaces': self.getBatmanInterfaces(self._config['batman'])
} }
}, },
"mac": lib.helper.getDevice_MAC(self._config["batman"]) 'mac': lib.helper.getInterfaceMAC(self._config['batman'])
}, },
"software": { 'software': {
"firmware": { 'firmware': {
"base": lib.helper.call(['lsb_release', '-is'])[0], 'base': lib.helper.call(['lsb_release', '-is'])[0],
"release": lib.helper.call(['lsb_release', '-ds'])[0] 'release': lib.helper.call(['lsb_release', '-ds'])[0]
}, },
"batman-adv": { 'batman-adv': {
"version": open('/sys/module/batman_adv/version').read().strip(), 'version': open('/sys/module/batman_adv/version').read().strip(),
# "compat": # /lib/gluon/mesh-batman-adv-core/compat # 'compat': # /lib/gluon/mesh-batman-adv-core/compat
}, },
"status-page": { 'status-page': {
"api": 0 'api': 0
}, },
"autoupdater": { 'autoupdater': {
"enabled": False 'enabled': False
} }
}, },
"hardware": { 'hardware': {
"model": self.getCPUInfo()["model name"], 'model': self.getCPUInfo()['model name'],
"nproc": int(lib.helper.call(['nproc'])[0]) 'nproc': int(lib.helper.call(['nproc'])[0])
}, },
"owner": {}, 'owner': {},
"system": {}, 'system': {},
"location": {} 'location': {},
'vpn': self.getVPN(self._config['batman'])
} }
if 'mesh-vpn' in self._config and len(self._config["mesh-vpn"]) > 0: if 'mesh-vpn' in self._config and len(self._config['mesh-vpn']) > 0:
try: try:
j["software"]["fastd"] = { ret['software']['fastd'] = {
"version": lib.helper.call(['fastd', '-v'])[0].split(' ')[1], 'version': lib.helper.call(['fastd', '-v'])[0].split(' ')[1],
"enabled": True 'enabled': True
} }
except: except:
pass pass
return lib.helper.merge(j, self._aliasOverlay["nodeinfo"]) return lib.helper.merge(ret, self._aliasOverlay['nodeinfo'])
...@@ -10,26 +10,25 @@ class Respondd: ...@@ -10,26 +10,25 @@ class Respondd:
self._config = config self._config = config
self._aliasOverlay = {} self._aliasOverlay = {}
try: try:
with open("alias.json", 'r') as fh: with open('alias.json', 'r') as fh:
self._aliasOverlay = json.load(fh) self._aliasOverlay = json.load(fh)
except IOError: except IOError:
raise raise
pass
def getNode_ID(self): def getNodeID(self):
if 'node_id' in self._aliasOverlay["nodeinfo"]: if 'node_id' in self._aliasOverlay['nodeinfo']:
return self._aliasOverlay["nodeinfo"]["node_id"] return self._aliasOverlay['nodeinfo']['node_id']
else: else:
return lib.helper.getDevice_MAC(self._config["batman"]).replace(':', '') return lib.helper.getInterfaceMAC(self._config['batman']).replace(':', '')
def getStruct(self, rootName=None): def getStruct(self, rootName=None):
j = self._get() ret = self._get()
j['node_id'] = self.getNode_ID() ret['node_id'] = self.getNodeID()
if not rootName is None: if rootName is not None:
j_tmp = j ret_tmp = ret
j = {} ret = {}
j[rootName] = j_tmp ret[rootName] = ret_tmp
return j return ret
def getJSON(self, rootName=None): def getJSON(self, rootName=None):
return bytes(json.dumps(self.getStruct(rootName), separators=(',', ':')), 'UTF-8') return bytes(json.dumps(self.getStruct(rootName), separators=(',', ':')), 'UTF-8')
...@@ -37,12 +36,14 @@ class Respondd: ...@@ -37,12 +36,14 @@ class Respondd:
def getJSONCompressed(self, rootName=None): def getJSONCompressed(self, rootName=None):
return self.compress(self.getJSON(rootName)) return self.compress(self.getJSON(rootName))
def compress(self, data): @staticmethod
def compress(data):
encoder = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -15) # The data may be decompressed using zlib and many zlib bindings using -15 as the window size parameter. encoder = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -15) # The data may be decompressed using zlib and many zlib bindings using -15 as the window size parameter.
dataGzip = encoder.compress(data) dataGzip = encoder.compress(data)
dataGzip += encoder.flush() dataGzip += encoder.flush()
return dataGzip return dataGzip
def _get(self): @staticmethod
def _get():
return {} return {}
pass
#!/usr/bin/env python3 #!/usr/bin/env python3
from lib.ratelimit import rateLimit
from lib.nodeinfo import Nodeinfo
from lib.neighbours import Neighbours
from lib.statistics import Statistics
import socket import socket
import select import select
import struct import struct
import json import json
from lib.ratelimit import rateLimit
from lib.nodeinfo import Nodeinfo
from lib.neighbours import Neighbours
from lib.statistics import Statistics
class ResponddClient: class ResponddClient:
def __init__(self, config): def __init__(self, config):
self._config = config self._config = config
if 'addr' in self._config:
addr = self._config['addr']
else:
addr = 'ff02::2:1001'
if 'addr' in self._config:
port = self._config['port']
else:
port = 1001
if_idx = socket.if_nametoindex(self._config["bridge"])
group = socket.inet_pton(socket.AF_INET6, addr) + struct.pack("I", if_idx)
self._sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
self._sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, group)
self._sock.bind(('::', port))
if 'rate_limit' in self._config: if 'rate_limit' in self._config:
if not 'rate_limit_burst' in self._config: if 'rate_limit_burst' not in self._config:
self._config['rate_limit_burst'] = 10 self._config['rate_limit_burst'] = 10
self.__RateLimit = rateLimit(self._config['rate_limit'], self._config['rate_limit_burst']) self.__RateLimit = rateLimit(self._config['rate_limit'], self._config['rate_limit_burst'])
else: else:
...@@ -42,12 +25,19 @@ class ResponddClient: ...@@ -42,12 +25,19 @@ class ResponddClient:
self._neighbours = Neighbours(self._config) self._neighbours = Neighbours(self._config)
self._statistics = Statistics(self._config) self._statistics = Statistics(self._config)
self._sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
def start(self): def start(self):
if_idx = socket.if_nametoindex(self._config['bridge'])
group = socket.inet_pton(socket.AF_INET6, self._config['addr']) + struct.pack('I', if_idx)
self._sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, group)
self._sock.bind(('::', self._config['port']))
while True: while True:
if select.select([self._sock], [], [], 1)[0]:
msg, sourceAddress = self._sock.recvfrom(2048) msg, sourceAddress = self._sock.recvfrom(2048)
msgSplit = str(msg, 'UTF-8').split(" ") msgSplit = str(msg, 'UTF-8').split(' ')
if msgSplit[0] == 'GET': # multi_request if msgSplit[0] == 'GET': # multi_request
for request in msgSplit[1:]: for request in msgSplit[1:]:
...@@ -56,8 +46,8 @@ class ResponddClient: ...@@ -56,8 +46,8 @@ class ResponddClient:
self.sendResponse(sourceAddress, msgSplit[0], False) self.sendResponse(sourceAddress, msgSplit[0], False)
def sendResponse(self, destAddress, responseType, withCompression): def sendResponse(self, destAddress, responseType, withCompression):
if not self.__RateLimit is None and not self.__RateLimit.limit(): if self.__RateLimit is not None and not self.__RateLimit.limit():
print("rate limit reached!") print('rate limit reached!')
return return
responseClass = None responseClass = None
...@@ -68,16 +58,16 @@ class ResponddClient: ...@@ -68,16 +58,16 @@ class ResponddClient:
elif responseType == 'neighbours': elif responseType == 'neighbours':
responseClass = self._neighbours responseClass = self._neighbours
else: else:
print("unknown command: " + responseType) print('unknown command: ' + responseType)
return return
if not self._config["dry_run"]: if not self._config['dry_run']:
if withCompression: if withCompression:
self._sock.sendto(responseClass.getJSONCompressed(responseType), destAddress) self._sock.sendto(responseClass.getJSONCompressed(responseType), destAddress)
else: else:
self._sock.sendto(responseClass.getJSON(responseType), destAddress) self._sock.sendto(responseClass.getJSON(responseType), destAddress)
if self._config["verbose"] or self._config["dry_run"]: if self._config['verbose'] or self._config['dry_run']:
print("%35s %5d %13s: " % (destAddress[0], destAddress[1], responseType), end='') print('%35s %5d %13s: ' % (destAddress[0], destAddress[1], responseType), end='')
print(json.dumps(responseClass.getStruct(responseType), sort_keys=True, indent=4)) print(json.dumps(responseClass.getStruct(responseType), sort_keys=True, indent=4))
#!/usr/bin/env python3 #!/usr/bin/env python3
import socket import socket
#import netifaces as netif
import subprocess
import re import re
import sys
import json
from lib.respondd import Respondd from lib.respondd import Respondd
import lib.helper import lib.helper
...@@ -14,14 +14,11 @@ class Statistics(Respondd): ...@@ -14,14 +14,11 @@ class Statistics(Respondd):
Respondd.__init__(self, config) Respondd.__init__(self, config)
def getClients(self): def getClients(self):
j = {"total": 0, "wifi": 0} ret = {'total': 0, 'wifi': 0}
batmanMAC = lib.helper.getDevice_MAC(self._config['batman']) macBridge = lib.helper.getInterfaceMAC(self._config['bridge'])
output = subprocess.check_output(["batctl", "-m", self._config['batman'], "tl", "-n"])
output_utf8 = output.decode("utf-8")
lines = output_utf8.splitlines()
lines = lib.helper.call(['batctl', '-m', self._config['batman'], 'tl', '-n'])
for line in lines: for line in lines:
# batman-adv -> translation-table.c -> batadv_tt_local_seq_print_text # batman-adv -> translation-table.c -> batadv_tt_local_seq_print_text
# R = BATADV_TT_CLIENT_ROAM # R = BATADV_TT_CLIENT_ROAM
...@@ -32,47 +29,84 @@ class Statistics(Respondd): ...@@ -32,47 +29,84 @@ class Statistics(Respondd):
# I = BATADV_TT_CLIENT_ISOLA # I = BATADV_TT_CLIENT_ISOLA
# . = unset # . = unset
# * c0:11:73:b2:8f:dd -1 [.P..W.] 1.710 (0xe680a836) # * c0:11:73:b2:8f:dd -1 [.P..W.] 1.710 (0xe680a836)
ml = re.match(r"^\s\*\s([0-9a-f:]+)\s+-\d\s\[([RPNXWI\.]+)\]", line, re.I) #d4:3d:7e:34:5c:b1 -1 [.P....] 0.000 (0x12a02817)
if ml: lineMatch = re.match(r'^[\s*]*([0-9a-f:]+)\s+-\d\s\[([RPNXWI\.]+)\]', line, re.I)
if not batmanMAC == ml.group(1): # Filter bat0 if lineMatch:
if not ml.group(1).startswith('33:33:') and not ml.group(1).startswith('01:00:5e:'): # Filter Multicast mac = lineMatch.group(1)
j["total"] += 1 flags = lineMatch.group(2)
if ml.group(2)[4] == 'W': if macBridge != mac and flags[0] != 'R': # Filter bridge and roaming clients
j["wifi"] += 1 if not mac.startswith('33:33:') and not mac.startswith('01:00:5e:'): # Filter Multicast
ret['total'] += 1
return j if flags[4] == 'W':
ret['wifi'] += 1
def getTraffic(self): # TODO: design rework needed!
return (lambda fields: dict( return ret
(key, dict(
(type_, int(value_)) def getTraffic(self):
for key_, type_, value_ in fields traffic = {}
if key_ == key)) lines = lib.helper.call(['ethtool', '-S', self._config['batman']])
for key in ['rx', 'tx', 'forward', 'mgmt_rx', 'mgmt_tx'] if len(lines) == 0:
))(list( return {}
( for line in lines[1:]:
key.replace('_bytes', '').replace('_dropped', ''), lineSplit = line.strip().split(':', 1)
'bytes' if key.endswith('_bytes') else 'dropped' if key.endswith('_dropped') else 'packets', name = lineSplit[0]
value value = lineSplit[1].strip()
) traffic[name] = value
for key, value in map(lambda s: list(map(str.strip, s.split(': ', 1))), lib.helper.call(['ethtool', '-S', self._config['batman']])[1:])
)) ret = {
'tx': {
def getMemory(self): # TODO: design rework needed! 'packets': traffic['tx'],
return dict( 'bytes': traffic['tx_bytes'],
(key.replace('Mem', '').lower(), int(value.split(' ')[0])) 'dropped': traffic['tx_dropped'],
for key, value in map(lambda s: map(str.strip, s.split(': ', 1)), open('/proc/meminfo').readlines()) },
if key in ('MemTotal', 'MemFree', 'Buffers', 'Cached') 'rx': {
) 'packets': traffic['rx'],
'bytes': traffic['rx_bytes'],
},
'forward': {
'packets': traffic['forward'],
'bytes': traffic['forward_bytes'],
},
'mgmt_rx': {
'packets': traffic['mgmt_rx'],
'bytes': traffic['mgmt_rx_bytes'],
},
'mgmt_tx': {
'packets': traffic['mgmt_tx'],
'bytes': traffic['mgmt_tx_bytes'],
},
}
return ret
@staticmethod
def getMemory():
ret = {}
lines = open('/proc/meminfo').readlines()
for line in lines:
lineSplit = line.split(' ', 1)
name = lineSplit[0][:-1]
value = lineSplit[1].strip().split(' ', 1)[0]
if name == 'MemTotal':
ret['total'] = value
elif name == 'MemFree':
ret['free'] = value
elif name == 'Buffers':
ret['buffers'] = value
elif name == 'Cached':
ret['cached'] = value
return ret
def getFastd(self): def getFastd(self):
dataFastd = b"" dataFastd = b''
try: try:
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(config["fastd_socket"]) sock.connect(self._config['fastd_socket'])
except socket.error as err: except socket.error as err:
print("socket error: ", sys.stderr, err) print('socket error: ', sys.stderr, err)
return None return None
while True: while True:
...@@ -82,54 +116,51 @@ class Statistics(Respondd): ...@@ -82,54 +116,51 @@ class Statistics(Respondd):
dataFastd += data dataFastd += data
sock.close() sock.close()
return json.loads(dataFastd.decode("utf-8")) return json.loads(dataFastd.decode('utf-8'))
def getMeshVPNPeers(self): def getMeshVPNPeers(self):
j = {} ret = {}
if "fastd_socket" in self._config: if 'fastd_socket' in self._config:
fastd = self.getFastd() fastd = self.getFastd()
for peer in fastd["peers"].values(): for peer in fastd['peers'].values():
if peer["connection"]: if peer['connection']:
j[peer["name"]] = { ret[peer['name']] = {
"established": peer["connection"]["established"] 'established': peer['connection']['established']
} }
else: else:
j[peer["name"]] = None ret[peer['name']] = None
return j return ret
else: else:
return None return None
def getGateway(self): def getGateway(self):
j = None ret = None
output = subprocess.check_output(["batctl", "-m", self._config['batman'], "gwl", "-n"])
output_utf8 = output.decode("utf-8")
lines = output_utf8.splitlines()
lines = lib.helper.call(['batctl', '-m', self._config['batman'], 'gwl', '-n'])
for line in lines: for line in lines:
gw_line = re.match(r"^(\*|=>) +([0-9a-f:]+) \([\d ]+\) ([0-9a-f:]+)", line) lineMatch = re.match(r'^(\*|=>) +([0-9a-f:]+) \([\d ]+\) ([0-9a-f:]+)', line)
if gw_line: if lineMatch:
j = {} ret = {}
j["gateway"] = gw_line.group(2) ret['gateway'] = lineMatch.group(2)
j["gateway_nexthop"] = gw_line.group(3) ret['gateway_nexthop'] = lineMatch.group(3)
return j return ret
def _get(self): def _get(self):
j = { ret = {
"clients": self.getClients(), 'clients': self.getClients(),
"traffic": self.getTraffic(), 'traffic': self.getTraffic(),
"idletime": float(open('/proc/uptime').read().split(' ')[1]), 'idletime': float(open('/proc/uptime').read().split(' ')[1]),
"loadavg": float(open('/proc/loadavg').read().split(' ')[0]), 'loadavg': float(open('/proc/loadavg').read().split(' ')[0]),
"memory": self.getMemory(), 'memory': self.getMemory(),
"processes": dict(zip(('running', 'total'), map(int, open('/proc/loadavg').read().split(' ')[3].split('/')))), 'processes': dict(zip(('running', 'total'), map(int, open('/proc/loadavg').read().split(' ')[3].split('/')))),
"uptime": float(open('/proc/uptime').read().split(' ')[0]), 'uptime': float(open('/proc/uptime').read().split(' ')[0]),
"mesh_vpn" : { # HopGlass-Server: node.flags.uplink = parsePeerGroup(_.get(n, 'statistics.mesh_vpn')) 'mesh_vpn' : { # HopGlass-Server: node.flags.uplink = parsePeerGroup(_.get(n, 'statistics.mesh_vpn'))
"groups": { 'groups': {
"backbone": { 'backbone': {
"peers": self.getMeshVPNPeers() 'peers': self.getMeshVPNPeers()
} }
} }
} }
...@@ -137,7 +168,7 @@ class Statistics(Respondd): ...@@ -137,7 +168,7 @@ class Statistics(Respondd):
gateway = self.getGateway() gateway = self.getGateway()
if gateway != None: if gateway != None:
j = lib.helper.merge(j, gateway) ret = lib.helper.merge(ret, gateway)
return j return ret
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment