Global: Change MAC address storage to use BIGINT

This requires changes to the MySQL database!

Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de>
This commit is contained in:
Adrian Schmutzler 2018-08-27 12:33:27 +02:00
parent 2a7d58413d
commit bc3460f2e0
16 changed files with 148 additions and 84 deletions

View File

@ -44,9 +44,9 @@ mysql.execute("""
mysql.execute(""" mysql.execute("""
CREATE TABLE gw_netif ( CREATE TABLE gw_netif (
`gw` smallint(5) UNSIGNED NOT NULL, `gw` smallint(5) UNSIGNED NOT NULL,
`mac` char(17) COLLATE utf8_unicode_ci NOT NULL, `mac` bigint(20) UNSIGNED NOT NULL,
`netif` varchar(15) COLLATE utf8_unicode_ci NOT NULL, `netif` varchar(15) COLLATE utf8_unicode_ci NOT NULL,
`vpnmac` char(17) COLLATE utf8_unicode_ci DEFAULT NULL, `vpnmac` bigint(20) UNSIGNED DEFAULT NULL,
`ipv4` char(18) COLLATE utf8_unicode_ci DEFAULT NULL, `ipv4` char(18) COLLATE utf8_unicode_ci DEFAULT NULL,
`ipv6` varchar(60) COLLATE utf8_unicode_ci DEFAULT NULL, `ipv6` varchar(60) COLLATE utf8_unicode_ci DEFAULT NULL,
`dhcpstart` char(15) COLLATE utf8_unicode_ci DEFAULT NULL, `dhcpstart` char(15) COLLATE utf8_unicode_ci DEFAULT NULL,

View File

@ -10,7 +10,7 @@ mysql = FreifunkMySQL()
mysql.execute(""" mysql.execute("""
CREATE TABLE banned ( CREATE TABLE banned (
`mac` char(17) COLLATE utf8_unicode_ci NOT NULL, `mac` bigint(20) UNSIGNED NOT NULL,
`added` datetime NOT NULL `added` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
""") """)
@ -22,7 +22,7 @@ mysql.execute("""
mysql.execute(""" mysql.execute("""
CREATE TABLE blocked ( CREATE TABLE blocked (
`mac` char(17) COLLATE utf8_unicode_ci NOT NULL, `mac` bigint(20) UNSIGNED NOT NULL,
`added` datetime NOT NULL `added` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
""") """)
@ -139,9 +139,9 @@ mysql.execute("""
mysql.execute(""" mysql.execute("""
CREATE TABLE router_gw ( CREATE TABLE router_gw (
`router` mediumint(8) UNSIGNED NOT NULL, `router` mediumint(8) UNSIGNED NOT NULL,
`mac` char(17) COLLATE utf8_unicode_ci NOT NULL, `mac` bigint(20) UNSIGNED NOT NULL,
`quality` float NOT NULL, `quality` float NOT NULL,
`nexthop` char(17) COLLATE utf8_unicode_ci DEFAULT NULL, `nexthop` bigint(20) UNSIGNED DEFAULT NULL,
`netif` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL, `netif` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL,
`gw_class` varchar(25) COLLATE utf8_unicode_ci DEFAULT NULL, `gw_class` varchar(25) COLLATE utf8_unicode_ci DEFAULT NULL,
`selected` tinyint(1) NOT NULL DEFAULT '0' `selected` tinyint(1) NOT NULL DEFAULT '0'
@ -169,7 +169,7 @@ mysql.execute("""
mysql.execute(""" mysql.execute("""
CREATE TABLE router_neighbor ( CREATE TABLE router_neighbor (
`router` mediumint(8) UNSIGNED NOT NULL, `router` mediumint(8) UNSIGNED NOT NULL,
`mac` char(17) COLLATE utf8_unicode_ci NOT NULL, `mac` bigint(20) UNSIGNED NOT NULL,
`netif` varchar(15) COLLATE utf8_unicode_ci NOT NULL, `netif` varchar(15) COLLATE utf8_unicode_ci NOT NULL,
`quality` float NOT NULL, `quality` float NOT NULL,
`type` varchar(10) COLLATE utf8_unicode_ci DEFAULT 'l2' `type` varchar(10) COLLATE utf8_unicode_ci DEFAULT 'l2'
@ -192,7 +192,7 @@ mysql.execute("""
`tx` int(10) UNSIGNED NOT NULL, `tx` int(10) UNSIGNED NOT NULL,
`fe80_addr` varchar(60) COLLATE utf8_unicode_ci NOT NULL, `fe80_addr` varchar(60) COLLATE utf8_unicode_ci NOT NULL,
`ipv4_addr` varchar(20) COLLATE utf8_unicode_ci NOT NULL, `ipv4_addr` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
`mac` char(17) COLLATE utf8_unicode_ci NOT NULL, `mac` bigint(20) UNSIGNED DEFAULT NULL,
`wlan_channel` tinyint(3) UNSIGNED DEFAULT NULL, `wlan_channel` tinyint(3) UNSIGNED DEFAULT NULL,
`wlan_type` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL, `wlan_type` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL,
`wlan_width` tinyint(3) UNSIGNED DEFAULT NULL, `wlan_width` tinyint(3) UNSIGNED DEFAULT NULL,
@ -236,7 +236,7 @@ mysql.execute("""
CREATE TABLE router_stats_gw ( CREATE TABLE router_stats_gw (
`time` int(11) NOT NULL, `time` int(11) NOT NULL,
`router` mediumint(8) UNSIGNED NOT NULL, `router` mediumint(8) UNSIGNED NOT NULL,
`mac` char(17) COLLATE utf8_unicode_ci NOT NULL, `mac` bigint(20) UNSIGNED NOT NULL,
`quality` float NOT NULL `quality` float NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
""") """)
@ -251,7 +251,7 @@ mysql.execute("""
CREATE TABLE router_stats_neighbor ( CREATE TABLE router_stats_neighbor (
`time` int(11) NOT NULL, `time` int(11) NOT NULL,
`router` mediumint(8) UNSIGNED NOT NULL, `router` mediumint(8) UNSIGNED NOT NULL,
`mac` char(17) COLLATE utf8_unicode_ci NOT NULL, `mac` bigint(20) UNSIGNED NOT NULL,
`quality` float NOT NULL `quality` float NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
""") """)

View File

@ -29,7 +29,7 @@ mysql.execute("""
mysql.execute(""" mysql.execute("""
CREATE TABLE stats_gw ( CREATE TABLE stats_gw (
`time` int(11) NOT NULL, `time` int(11) NOT NULL,
`mac` char(17) COLLATE utf8_unicode_ci NOT NULL, `mac` bigint(20) UNSIGNED NOT NULL,
`clients` mediumint(9) NOT NULL, `clients` mediumint(9) NOT NULL,
`online` smallint(6) NOT NULL, `online` smallint(6) NOT NULL,
`offline` smallint(6) NOT NULL, `offline` smallint(6) NOT NULL,

View File

@ -39,7 +39,7 @@ def import_gw_data(mysql, gw_data):
ndata = [] ndata = []
for n in gw_data["netifs"]: for n in gw_data["netifs"]:
if len(n["mac"])<17: if len(n["mac"])<17 or len(n["mac"])>17:
continue continue
if n["netif"].startswith("l2tp"): # Filter l2tp interfaces if n["netif"].startswith("l2tp"): # Filter l2tp interfaces
continue continue
@ -56,7 +56,7 @@ def import_gw_data(mysql, gw_data):
if not "dhcpend" in n or not n["dhcpend"]: if not "dhcpend" in n or not n["dhcpend"]:
n["dhcpend"] = None n["dhcpend"] = None
ndata.append((newid,n["mac"],n["netif"],n["vpnmac"],n["ipv4"],n["ipv6"],n["dhcpstart"],n["dhcpend"],time,)) ndata.append((newid,mac2int(n["mac"]),n["netif"],mac2int(n["vpnmac"]),n["ipv4"],n["ipv6"],n["dhcpstart"],n["dhcpend"],time,))
mysql.executemany(""" mysql.executemany("""
INSERT INTO gw_netif (gw, mac, netif, vpnmac, ipv4, ipv6, dhcpstart, dhcpend, last_contact) INSERT INTO gw_netif (gw, mac, netif, vpnmac, ipv4, ipv6, dhcpstart, dhcpend, last_contact)
@ -92,12 +92,12 @@ def gw_name(gw):
if gw["gw"] and gw["gwif"]: if gw["gw"] and gw["gwif"]:
s = gw["gw"] + " (" + gw["gwif"] + ")" s = gw["gw"] + " (" + gw["gwif"] + ")"
else: else:
s = gw["mac"] s = int2mac(gw["mac"])
return s return s
def gw_bat(gw): def gw_bat(gw):
if gw["batif"] and gw["batmac"]: if gw["batif"] and gw["batmac"]:
s = gw["batmac"] + " (" + gw["batif"] + ")" s = int2mac(gw["batmac"]) + " (" + gw["batif"] + ")"
else: else:
s = "---" s = "---"
return s return s

View File

@ -8,6 +8,48 @@ from ffmap.config import CONFIG
def utcnow(): def utcnow():
return datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc) return datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc)
def int2mac(data,keys=None):
if keys:
for k in keys:
data[k] = int2mac(data[k])
return data
if data:
return ':'.join(format(s, '02x') for s in data.to_bytes(6,byteorder='big'))
#return ':'.join(format(s, '02x') for s in bytes.fromhex('{0:x}'.format(data)))
else:
return ''
def int2shortmac(data,keys=None):
if keys:
for k in keys:
data[k] = int2shortmac(data[k])
return data
if data:
return '{:012x}'.format(data)
else:
return ''
def shortmac2mac(data):
if data:
return ':'.join(format(s, '02x') for s in bytes.fromhex(data.replace(':','')))
else:
return ''
def mac2int(data):
if data:
return int(data.replace(":",""),16)
else:
return None
def int2mactuple(data,index=None):
if index:
for r in data:
r[index] = int2mac(r[index])
else:
for r in data:
r = int2mac(r)
return data
def writelog(path, content): def writelog(path, content):
with open(path, "a") as csv: with open(path, "a") as csv:
csv.write(time.strftime('{%Y-%m-%d %H:%M:%S}') + " - " + content + "\n") csv.write(time.strftime('{%Y-%m-%d %H:%M:%S}') + " - " + content + "\n")

View File

@ -125,5 +125,3 @@ class FreifunkMySQL:
#r = pytz.utc.localize(r) #r = pytz.utc.localize(r)
r = r.replace(tzinfo=datetime.timezone.utc) r = r.replace(tzinfo=datetime.timezone.utc)
return data return data

View File

@ -62,7 +62,7 @@ def import_nodewatcher_xml(mysql, mac, xml, banned, netifdict, statstime):
reset = False reset = False
try: try:
findrouter = mysql.findone("SELECT router FROM router_netif WHERE mac = %s LIMIT 1",(mac.lower(),)) findrouter = mysql.findone("SELECT router FROM router_netif WHERE mac = %s LIMIT 1",(mac2int(mac),))
router_update = parse_nodewatcher_xml(xml,statstime) router_update = parse_nodewatcher_xml(xml,statstime)
# cancel if banned mac found # cancel if banned mac found
@ -798,7 +798,7 @@ def parse_nodewatcher_xml(xml,statstime):
"tx": 0, "tx": 0,
}, },
"ipv4_addr": evalxpath(netif,"ipv4_addr/text()"), "ipv4_addr": evalxpath(netif,"ipv4_addr/text()"),
"mac": evalxpath(netif,"mac_addr/text()").lower(), "mac": mac2int(evalxpath(netif,"mac_addr/text()")),
"wlan_channel": evalxpathint(netif,"wlan_channel/text()",None), "wlan_channel": evalxpathint(netif,"wlan_channel/text()",None),
"wlan_type": evalxpath(netif,"wlan_type/text()",None), "wlan_type": evalxpath(netif,"wlan_type/text()",None),
"wlan_width": evalxpathint(netif,"wlan_width/text()",None), "wlan_width": evalxpathint(netif,"wlan_width/text()",None),
@ -819,12 +819,12 @@ def parse_nodewatcher_xml(xml,statstime):
for originator in tree.xpath("/data/batman_adv_originators/*"): for originator in tree.xpath("/data/batman_adv_originators/*"):
visible_neighbours += 1 visible_neighbours += 1
o_mac = evalxpath(originator,"originator/text()") o_mac = mac2int(evalxpath(originator,"originator/text()"))
o_nexthop = evalxpath(originator,"nexthop/text()") o_nexthop = mac2int(evalxpath(originator,"nexthop/text()"))
# mac is the mac of the neighbour w2/5mesh if # mac is the mac of the neighbour w2/5mesh if
# (which might also be called wlan0-1) # (which might also be called wlan0-1)
o_out_if = evalxpath(originator,"outgoing_interface/text()") o_out_if = evalxpath(originator,"outgoing_interface/text()")
if o_mac.upper() == o_nexthop.upper(): if o_mac == o_nexthop:
# skip vpn server # skip vpn server
if o_out_if == CONFIG["vpn_netif"]: if o_out_if == CONFIG["vpn_netif"]:
continue continue
@ -833,7 +833,7 @@ def parse_nodewatcher_xml(xml,statstime):
elif o_out_if == CONFIG["vpn_netif_aux"]: elif o_out_if == CONFIG["vpn_netif_aux"]:
continue continue
neighbour = { neighbour = {
"mac": o_mac.lower(), "mac": o_mac,
"netif": o_out_if, "netif": o_out_if,
"quality": evalxpathfloat(originator,"link_quality/text()"), "quality": evalxpathfloat(originator,"link_quality/text()"),
"type": "l2" "type": "l2"
@ -849,10 +849,12 @@ def parse_nodewatcher_xml(xml,statstime):
for gw in tree.xpath("/data/batman_adv_gateway_list/*"): for gw in tree.xpath("/data/batman_adv_gateway_list/*"):
gw_mac = evalxpath(gw,"gateway/text()") gw_mac = evalxpath(gw,"gateway/text()")
if (gw_mac and len(gw_mac)>12): # Throw away headline if (gw_mac and len(gw_mac)>12): # Throw away headline
if len(gw_mac) > 17:
gw_mac = gw_mac[0:17]
gw = { gw = {
"mac": gw_mac.lower(), "mac": mac2int(gw_mac),
"quality": evalxpath(gw,"link_quality/text()"), "quality": evalxpath(gw,"link_quality/text()"),
"nexthop": evalxpath(gw,"nexthop/text()",None), "nexthop": mac2int(evalxpath(gw,"nexthop/text()",None)),
"netif": evalxpath(gw,"outgoing_interface/text()",None), "netif": evalxpath(gw,"outgoing_interface/text()",None),
"gw_class": evalxpath(gw,"gw_class/text()",None), "gw_class": evalxpath(gw,"gw_class/text()",None),
"selected": evalxpathbool(gw,"selected/text()") "selected": evalxpathbool(gw,"selected/text()")
@ -886,7 +888,7 @@ def get_l3_neighbours(tree):
if not iptmp: if not iptmp:
iptmp = neighbour.text iptmp = neighbour.text
neighbour = { neighbour = {
"mac": get_mac_from_v6_link_local(iptmp).lower(), "mac": mac2int(get_mac_from_v6_link_local(iptmp)),
"netif": neighbour.xpath("outgoing_interface/text()")[0], "netif": neighbour.xpath("outgoing_interface/text()")[0],
"quality": -1.0*evalxpathfloat(neighbour,"link_cost/text()",1), "quality": -1.0*evalxpathfloat(neighbour,"link_cost/text()",1),
"type": "l3" "type": "l3"
@ -894,7 +896,6 @@ def get_l3_neighbours(tree):
l3_neighbours.append(neighbour) l3_neighbours.append(neighbour)
return l3_neighbours return l3_neighbours
def get_mac_from_v6_link_local(v6_fe80): def get_mac_from_v6_link_local(v6_fe80):
fullip = ipaddress.ip_address(v6_fe80).exploded fullip = ipaddress.ip_address(v6_fe80).exploded
first = '%02x' % (int(fullip[20:22], 16) ^ 2) first = '%02x' % (int(fullip[20:22], 16) ^ 2)

View File

@ -162,7 +162,7 @@ def router_models(mysql,selecthood=None,selectgw=None):
WHERE mac = %s WHERE mac = %s
GROUP BY hardware GROUP BY hardware
ORDER BY hardware ORDER BY hardware
""",(selectgw,),"hardware") """,(mac2int(selectgw),),"hardware")
else: else:
return mysql.fetchdict(""" return mysql.fetchdict("""
SELECT hardware, COUNT(id) AS count, SUM(clients) AS clients SELECT hardware, COUNT(id) AS count, SUM(clients) AS clients
@ -188,7 +188,7 @@ def router_firmwares(mysql,selecthood=None,selectgw=None):
WHERE mac = %s WHERE mac = %s
GROUP BY firmware GROUP BY firmware
ORDER BY firmware ORDER BY firmware
""",(selectgw,),"firmware","count") """,(mac2int(selectgw),),"firmware","count")
else: else:
return mysql.fetchdict(""" return mysql.fetchdict("""
SELECT firmware, COUNT(id) AS count SELECT firmware, COUNT(id) AS count
@ -342,7 +342,7 @@ def gws_admin(mysql,selectgw):
INNER JOIN gw_admin ON gw_netif.gw = gw_admin.gw INNER JOIN gw_admin ON gw_netif.gw = gw_admin.gw
WHERE mac = %s WHERE mac = %s
ORDER BY prio ASC ORDER BY prio ASC
""",(selectgw,),"name") """,(mac2int(selectgw),),"name")
return data return data
def record_global_stats(mysql): def record_global_stats(mysql):

View File

@ -6,7 +6,7 @@ from ffmap.maptools import *
from ffmap.mysqltools import FreifunkMySQL from ffmap.mysqltools import FreifunkMySQL
from ffmap.stattools import record_global_stats, record_hood_stats from ffmap.stattools import record_global_stats, record_hood_stats
from ffmap.config import CONFIG from ffmap.config import CONFIG
from ffmap.misc import writelog, writefulllog, neighbor_color from ffmap.misc import *
from flask import Blueprint, request, make_response, redirect, url_for, jsonify, Response from flask import Blueprint, request, make_response, redirect, url_for, jsonify, Response
from bson.json_util import dumps as bson2json from bson.json_util import dumps as bson2json
@ -121,7 +121,7 @@ def get_router_by_mac(mac):
INNER JOIN router_netif ON router.id = router_netif.router INNER JOIN router_netif ON router.id = router_netif.router
WHERE mac = %s WHERE mac = %s
GROUP BY mac, id GROUP BY mac, id
""",(mac.lower(),)) """,(mac2int(mac),))
mysql.close() mysql.close()
if len(res_routers) != 1: if len(res_routers) != 1:
return redirect(url_for("router_list", q="mac:%s" % mac)) return redirect(url_for("router_list", q="mac:%s" % mac))
@ -279,13 +279,13 @@ def wifianalhelper(router_data, headline):
if not router['mac']: if not router['mac']:
continue continue
if router["netif"] == 'br-mesh': if router["netif"] == 'br-mesh':
s += router["mac"] + "|Mesh_" + router['hostname'] + "\n" s += int2mac(router["mac"]) + "|Mesh_" + router['hostname'] + "\n"
elif router["netif"] == 'w2ap': elif router["netif"] == 'w2ap':
s += router["mac"] + "|" + router['hostname'] + "\n" s += int2mac(router["mac"]) + "|" + router['hostname'] + "\n"
elif router["netif"] == 'w5ap': elif router["netif"] == 'w5ap':
s += router["mac"] + "|W5_" + router['hostname'] + "\n" s += int2mac(router["mac"]) + "|W5_" + router['hostname'] + "\n"
elif router["netif"] == 'w5mesh': elif router["netif"] == 'w5mesh':
s += router["mac"] + "|W5Mesh_" + router['hostname'] + "\n" s += int2mac(router["mac"]) + "|W5Mesh_" + router['hostname'] + "\n"
return Response(s,mimetype='text/plain') return Response(s,mimetype='text/plain')
@ -304,7 +304,7 @@ def dnslist():
s = "" s = ""
for router in router_data: for router in router_data:
s += router["mac"].replace(":","") + "\t" + router["fd43"] + "\n" s += int2shortmac(router["mac"]) + "\t" + router["fd43"] + "\n"
return Response(s,mimetype='text/plain') return Response(s,mimetype='text/plain')
@ -323,7 +323,7 @@ def dnsentries():
s = "" s = ""
for router in router_data: for router in router_data:
s += router["mac"].replace(":","") + ".fff.community. 300 IN AAAA " + router["fd43"] + " ; " + router["hostname"] + "\n" s += int2shortmac(router["mac"]) + ".fff.community. 300 IN AAAA " + router["fd43"] + " ; " + router["hostname"] + "\n"
return Response(s,mimetype='text/plain') return Response(s,mimetype='text/plain')
@ -367,18 +367,21 @@ def routers():
#elif netif['netif'] == 'br-mesh' and 'mac' in netif: #elif netif['netif'] == 'br-mesh' and 'mac' in netif:
# mac = netif["mac"] # mac = netif["mac"]
if not router['mac']:
continue
nodelist_data['nodes'].append( nodelist_data['nodes'].append(
{ {
'id': str(router['id']), 'id': str(router['id']),
'name': router['hostname'], 'name': router['hostname'],
'mac': router['mac'], 'mac': int2mac(router['mac']),
'hood': router['hood'], 'hood': router['hood'],
'status': router['status'], 'status': router['status'],
'user': router['nickname'], 'user': router['nickname'],
'hardware': router['hardware'], 'hardware': router['hardware'],
'firmware': router['firmware'], 'firmware': router['firmware'],
'loadavg': router['sys_loadavg'], 'loadavg': router['sys_loadavg'],
'href': 'https://monitoring.freifunk-franken.de/mac/' + router['mac'], 'href': 'https://monitoring.freifunk-franken.de/mac/' + int2shortmac(router['mac']),
'clients': router['clients'], 'clients': router['clients'],
'lastcontact': router['last_contact'].isoformat(), 'lastcontact': router['last_contact'].isoformat(),
'uplink': { 'uplink': {
@ -454,7 +457,7 @@ def get_routers_by_nickname(nickname):
{ {
'name': router['hostname'], 'name': router['hostname'],
'oid': str(router['id']), 'oid': str(router['id']),
'mac': router['mac'], 'mac': int2mac(router['mac']),
'ipv6_fe80_addr': router['fe80_addr'] 'ipv6_fe80_addr': router['fe80_addr']
} }
) )

View File

@ -13,7 +13,7 @@ from ffmap.routertools import delete_router, ban_router
from ffmap.gwtools import gw_name, gw_bat from ffmap.gwtools import gw_name, gw_bat
from ffmap.web.helpers import * from ffmap.web.helpers import *
from ffmap.config import CONFIG from ffmap.config import CONFIG
from ffmap.misc import writelog, writefulllog, neighbor_color from ffmap.misc import *
from flask import Flask, render_template, request, Response, redirect, url_for, flash, session from flask import Flask, render_template, request, Response, redirect, url_for, flash, session
import bson import bson
@ -79,7 +79,7 @@ def router_mac(mac):
INNER JOIN router_netif ON router.id = router_netif.router INNER JOIN router_netif ON router.id = router_netif.router
WHERE mac = %s WHERE mac = %s
GROUP BY mac, id GROUP BY mac, id
""",(mac.lower(),)) """,(mac2int(mac),))
mysql.close() mysql.close()
if len(res_routers) != 1: if len(res_routers) != 1:
return redirect(url_for("router_list", q="mac:%s" % mac)) return redirect(url_for("router_list", q="mac:%s" % mac))
@ -486,7 +486,8 @@ def global_hoodstatistics(selecthood):
@app.route('/gwstatistics/<selectgw>') @app.route('/gwstatistics/<selectgw>')
def global_gwstatistics(selectgw): def global_gwstatistics(selectgw):
mysql = FreifunkMySQL() mysql = FreifunkMySQL()
stats = mysql.fetchall("SELECT * FROM stats_gw WHERE mac = %s",(selectgw,)) stats = mysql.fetchall("SELECT * FROM stats_gw WHERE mac = %s",(mac2int(selectgw),))
selectgw = shortmac2mac(selectgw)
return helper_statistics(mysql,stats,None,selectgw) return helper_statistics(mysql,stats,None,selectgw)
def helper_statistics(mysql,stats,selecthood,selectgw): def helper_statistics(mysql,stats,selecthood,selectgw):
@ -494,10 +495,15 @@ def helper_statistics(mysql,stats,selecthood,selectgw):
hoods = stattools.hoods(mysql,selectgw) hoods = stattools.hoods(mysql,selectgw)
gws = stattools.gws(mysql,selecthood) gws = stattools.gws(mysql,selecthood)
if selectgw:
selectgwint = mac2int(selectgw)
else:
selectgwint = None
if selecthood and not selecthood in hoods: if selecthood and not selecthood in hoods:
mysql.close() mysql.close()
return "Hood not found" return "Hood not found"
if selectgw and not selectgw in gws: if selectgw and not selectgwint in gws:
mysql.close() mysql.close()
return "Gateway not found" return "Gateway not found"
@ -515,7 +521,7 @@ def helper_statistics(mysql,stats,selecthood,selectgw):
WHERE hardware <> 'Legacy' AND mac = %s WHERE hardware <> 'Legacy' AND mac = %s
ORDER BY created DESC ORDER BY created DESC
LIMIT %s LIMIT %s
""",(selectgw,numnew,)) """,(mac2int(selectgw),numnew,))
else: else:
if selecthood: if selecthood:
where = " AND hood = %s" where = " AND hood = %s"
@ -546,6 +552,7 @@ def helper_statistics(mysql,stats,selecthood,selectgw):
return render_template("statistics.html", return render_template("statistics.html",
selecthood = selecthood, selecthood = selecthood,
selectgw = selectgw, selectgw = selectgw,
selectgwint = selectgwint,
stats = stats, stats = stats,
clients = clients, clients = clients,
router_status = router_status, router_status = router_status,

View File

@ -9,6 +9,7 @@ import json
import datetime import datetime
import re import re
import hashlib import hashlib
from ffmap.misc import int2mac, int2shortmac
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + '/' + '../..')) sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + '/' + '../..'))
from ffmap.misc import * from ffmap.misc import *
@ -19,6 +20,14 @@ filters = Blueprint("filters", __name__)
def sumdict(d): def sumdict(d):
return sum(d.values()) return sum(d.values())
@filters.app_template_filter('int2mac')
def int2macfilter(d):
return int2mac(d)
@filters.app_template_filter('int2shortmac')
def int2shortmacfilter(d):
return int2shortmac(d)
@filters.app_template_filter('utc2local') @filters.app_template_filter('utc2local')
def utc2local(dt): def utc2local(dt):
return dt.astimezone(tz.tzlocal()) return dt.astimezone(tz.tzlocal())
@ -115,7 +124,12 @@ def mac_to_ipv6_linklocal(mac):
# Remove the most common delimiters; dots, dashes, etc. # Remove the most common delimiters; dots, dashes, etc.
mac_bare = re.sub('[%s]+' % re.escape(' .:-'), '', mac) mac_bare = re.sub('[%s]+' % re.escape(' .:-'), '', mac)
mac_value = int(mac_bare, 16) return macint_to_ipv6_linklocal(int(mac_bare, 16))
@filters.app_template_filter('macint2fe80')
def macint_to_ipv6_linklocal(mac_value):
if not mac_value:
return ''
# Split out the bytes that slot into the IPv6 address # Split out the bytes that slot into the IPv6 address
# XOR the most significant byte with 0x02, inverting the # XOR the most significant byte with 0x02, inverting the

View File

@ -68,16 +68,16 @@ def parse_router_list_search_query(args):
k = key + ' = "" OR ' + key + " IS NULL" k = key + ' = "" OR ' + key + " IS NULL"
elif key == 'mac': elif key == 'mac':
j += " INNER JOIN ( SELECT router, mac FROM router_netif GROUP BY router, mac) AS j ON router.id = j.router " j += " INNER JOIN ( SELECT router, mac FROM router_netif GROUP BY router, mac) AS j ON router.id = j.router "
k = "mac {} REGEXP %s".format(no) k = "HEX(mac) {} REGEXP %s".format(no)
t.append(value.lower()) t.append(value.replace(':',''))
elif (key == 'gw'): elif (key == 'gw'):
j += " INNER JOIN router_gw ON router.id = router_gw.router " j += " INNER JOIN router_gw ON router.id = router_gw.router "
k = "router_gw.mac {} REGEXP %s".format(no) k = "HEX(router_gw.mac) {} REGEXP %s".format(no)
t.append(value.lower()) t.append(value.replace(':',''))
elif (key == 'selected'): elif (key == 'selected'):
j += " INNER JOIN router_gw ON router.id = router_gw.router " j += " INNER JOIN router_gw ON router.id = router_gw.router "
k = "router_gw.mac {} REGEXP %s AND router_gw.selected = TRUE".format(no) k = "HEX(router_gw.mac) {} REGEXP %s AND router_gw.selected = TRUE".format(no)
t.append(value.lower()) t.append(value.replace(':',''))
elif (key == 'bat'): elif (key == 'bat'):
j += """ INNER JOIN router_gw ON router.id = router_gw.router j += """ INNER JOIN router_gw ON router.id = router_gw.router
INNER JOIN ( INNER JOIN (
@ -85,8 +85,8 @@ def parse_router_list_search_query(args):
INNER JOIN gw_netif AS n2 ON n1.mac = n2.vpnmac AND n1.gw = n2.gw INNER JOIN gw_netif AS n2 ON n1.mac = n2.vpnmac AND n1.gw = n2.gw
) ON router_gw.mac = n1.mac ) ON router_gw.mac = n1.mac
""" """
k = "n2.mac {} REGEXP %s".format(no) k = "HEX(n2.mac) {} REGEXP %s".format(no)
t.append(value.lower()) t.append(value.replace(':',''))
elif (key == 'batselected'): elif (key == 'batselected'):
j += """ INNER JOIN router_gw ON router.id = router_gw.router j += """ INNER JOIN router_gw ON router.id = router_gw.router
INNER JOIN ( INNER JOIN (
@ -94,12 +94,12 @@ def parse_router_list_search_query(args):
INNER JOIN gw_netif AS n2 ON n1.mac = n2.vpnmac AND n1.gw = n2.gw INNER JOIN gw_netif AS n2 ON n1.mac = n2.vpnmac AND n1.gw = n2.gw
) ON router_gw.mac = n1.mac ) ON router_gw.mac = n1.mac
""" """
k = "n2.mac {} REGEXP %s AND router_gw.selected = TRUE".format(no) k = "HEX(n2.mac) {} REGEXP %s AND router_gw.selected = TRUE".format(no)
t.append(value.lower()) t.append(value.replace(':',''))
elif (key == 'neighbor') or (key == 'neighbour'): elif (key == 'neighbor') or (key == 'neighbour'):
j += " INNER JOIN ( SELECT router, mac FROM router_neighbor GROUP BY router, mac) AS j ON router.id = j.router " j += " INNER JOIN ( SELECT router, mac FROM router_neighbor GROUP BY router, mac) AS j ON router.id = j.router "
k = "mac {} REGEXP %s".format(no) k = "HEX(mac) {} REGEXP %s".format(no)
t.append(value.lower()) t.append(value.replace(':',''))
elif (key == 'hardware') or (key == 'hood') or (key == 'nickname'): elif (key == 'hardware') or (key == 'hood') or (key == 'nickname'):
k = key + " {} REGEXP %s".format(no) k = key + " {} REGEXP %s".format(no)
t.append(value.replace("_",".")) t.append(value.replace("_","."))

View File

@ -102,7 +102,6 @@ function neighbour_graph(neigh_label) {
var meshstat = $("#meshstat"); var meshstat = $("#meshstat");
var pdata = []; var pdata = [];
var len, i; var len, i;
var mac;
for (var j in neigh_stats) { for (var j in neigh_stats) {
var dataset = neigh_stats[j]; var dataset = neigh_stats[j];

View File

@ -147,7 +147,7 @@ map.on('click', function(pos) {
// skip unknown neighbours // skip unknown neighbours
if ('id' in neighbour) { if ('id' in neighbour) {
popup_html += "<tr style=\"background-color: "+neighbour.color+";\">"; popup_html += "<tr style=\"background-color: "+neighbour.color+";\">";
popup_html += '<td><a href="'+url_router_info+neighbour.id+'" title="'+escapeHTML(neighbour.mac)+'" style="color:#000000">'+escapeHTML(neighbour.hostname)+'</a></td>'; popup_html += '<td><a href="'+url_router_info+neighbour.id+'" title="'+escapeHTML(neighbour.mac)+'" style="color:#000000">'+escapeHTML(neighbour.hostname)+'</a></td>'; // MACTODO
popup_html += "<td>"+neighbour.quality+"</td>"; popup_html += "<td>"+neighbour.quality+"</td>";
popup_html += "<td>"+escapeHTML(neighbour.netif)+"</td>"; popup_html += "<td>"+escapeHTML(neighbour.netif)+"</td>";
popup_html += "</tr>"; popup_html += "</tr>";

View File

@ -51,7 +51,7 @@
<div class="col-xs-12 col-sm-10"> <div class="col-xs-12 col-sm-10">
<h2 style="margin-top: 10px;">{%- if router.gateway %}Gateway{%- else %}Router{%- endif %}: {{ router.hostname }}</h2> <h2 style="margin-top: 10px;">{%- if router.gateway %}Gateway{%- else %}Router{%- endif %}: {{ router.hostname }}</h2>
{%- if mac %} {%- if mac %}
<h4 style="margin-top: 10px;margin-bottom: 20px">Perma-Link: <a href="{{ url_for('router_mac', mac=mac, _external=True) }}">{{ url_for('router_mac', mac=mac, _external=True) }}</a></h4> <h4 style="margin-top: 10px;margin-bottom: 20px">Perma-Link: <a href="{{ url_for('router_mac', mac=mac|int2shortmac, _external=True) }}">{{ url_for('router_mac', mac=mac|int2shortmac, _external=True) }}</a></h4>
{%- endif %} {%- endif %}
</div> </div>
<div class="col-xs-12 col-sm-2 text-right" style="margin-top: 10px; margin-bottom: 10px;"> <div class="col-xs-12 col-sm-2 text-right" style="margin-top: 10px; margin-bottom: 10px;">
@ -240,7 +240,7 @@
<tr style="background-color: {{ neighbour.color }};"> <tr style="background-color: {{ neighbour.color }};">
<td>{%- if neighbour.hostname -%}<a href="{{ url_for('router_info', dbid=neighbour.id) }}" style="color:#000000">{{ neighbour.hostname }}</a>{%- else -%}---{%- endif -%}</td> <td>{%- if neighbour.hostname -%}<a href="{{ url_for('router_info', dbid=neighbour.id) }}" style="color:#000000">{{ neighbour.hostname }}</a>{%- else -%}---{%- endif -%}</td>
<td>{{ neighbour.mac }}</td> <td>{{ neighbour.mac|int2mac }}</td>
<td>{{ neighbour.quality }}</td> <td>{{ neighbour.quality }}</td>
<td>{{ neighbour.netif }}</td> <td>{{ neighbour.netif }}</td>
</tr> </tr>
@ -272,14 +272,14 @@
<li class="list-group-item active" data-name="{{ netif.netif|replace('.', '')|replace('$', '') }}"> <li class="list-group-item active" data-name="{{ netif.netif|replace('.', '')|replace('$', '') }}">
<div class="row"> <div class="row">
<div class="col-xs-7 col-sm-7"><h4 class="list-group-item-heading">br-mesh: <span class="netifdesc">Bridge</span></h4></div> <div class="col-xs-7 col-sm-7"><h4 class="list-group-item-heading">br-mesh: <span class="netifdesc">Bridge</span></h4></div>
<div class="col-xs-5 col-sm-5 text-right" style="text-transform: uppercase;"><h4 class="list-group-item-heading">{{ netif.mac }}</h4></div> <div class="col-xs-5 col-sm-5 text-right" style="text-transform: uppercase;"><h4 class="list-group-item-heading">{{ netif.mac|int2mac }}</h4></div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-5 col-sm-5"> <div class="col-xs-5 col-sm-5">
{%- if netif.ipv6_fe80_addr -%} {%- if netif.ipv6_fe80_addr -%}
{{ netif.ipv6_fe80_addr }} {{ netif.ipv6_fe80_addr }}
{%- else -%} {%- else -%}
<em title="Calculated from MAC Address">{{ netif.mac|mac2fe80 }}</em> <em title="Calculated from MAC Address">{{ netif.mac|macint2fe80 }}</em>
{%- endif -%} {%- endif -%}
{%- if netif.ipv4_addr -%} {%- if netif.ipv4_addr -%}
<br />{{ netif.ipv4_addr }} <br />{{ netif.ipv4_addr }}
@ -301,7 +301,7 @@
<li class="list-group-item" data-name="{{ netif.netif|replace('.', '')|replace('$', '') }}"> <li class="list-group-item" data-name="{{ netif.netif|replace('.', '')|replace('$', '') }}">
<div class="row"> <div class="row">
<div class="col-xs-7 col-sm-7"><h4 class="list-group-item-heading" style="{%- if netif.color -%}color:{{ netif.color }}{%- endif -%}">{{ netif.netif }}{%- if netif.description -%}: <span class="netifdesc">{{ netif.description }}</span>{%- endif %}</h4></div> <div class="col-xs-7 col-sm-7"><h4 class="list-group-item-heading" style="{%- if netif.color -%}color:{{ netif.color }}{%- endif -%}">{{ netif.netif }}{%- if netif.description -%}: <span class="netifdesc">{{ netif.description }}</span>{%- endif %}</h4></div>
<div class="col-xs-5 col-sm-5 text-right" style="text-transform: uppercase;"><h4 class="list-group-item-heading">{{ netif.mac }}</h4></div> <div class="col-xs-5 col-sm-5 text-right" style="text-transform: uppercase;"><h4 class="list-group-item-heading">{{ netif.mac|int2mac }}</h4></div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-sm-12" style="padding-bottom:6px;font-size:14px"> <div class="col-xs-12 col-sm-12" style="padding-bottom:6px;font-size:14px">
@ -324,7 +324,7 @@
{%- if netif.ipv6_fe80_addr -%} {%- if netif.ipv6_fe80_addr -%}
{{ netif.ipv6_fe80_addr }} {{ netif.ipv6_fe80_addr }}
{%- else -%} {%- else -%}
<em title="Calculated from MAC Address">{{ netif.mac|mac2fe80 }}</em> <em title="Calculated from MAC Address">{{ netif.mac|macint2fe80 }}</em>
{%- endif -%} {%- endif -%}
{%- if netif.ipv4_addr -%} {%- if netif.ipv4_addr -%}
<br />{{ netif.ipv4_addr }} <br />{{ netif.ipv4_addr }}
@ -363,7 +363,7 @@
{%- else %} {%- else %}
<tr> <tr>
{%- endif %} {%- endif %}
<td><a href="{{ url_for('router_list', q='selected:^%s$' % gw.mac) }}">{{ gw.label }}</a></td> <td><a href="{{ url_for('router_list', q='selected:^%s$' % gw.mac|int2shortmac) }}">{{ gw.label }}</a></td>
<td>{{ gw.batX }}</td> <td>{{ gw.batX }}</td>
<td>{{ gw.quality }}</td> <td>{{ gw.quality }}</td>
<td>{{ gw.netif }}</td> <td>{{ gw.netif }}</td>
@ -424,7 +424,7 @@
var gw_stats = {{ gwstats|statbson2json|safe }}; var gw_stats = {{ gwstats|statbson2json|safe }};
var neighbours = [ var neighbours = [
{%- for neighbour in router.neighbours %} {%- for neighbour in router.neighbours %}
{"name": "{{ neighbour.hostname or neighbour.mac }}", "mac": "{{ neighbour.mac }}", "netif": "{{ neighbour.netif }}"}, {"name": "{{ neighbour.hostname or neighbour.mac|int2mac }}", "mac": "{{ neighbour.mac }}", "netif": "{{ neighbour.netif }}"},
{%- endfor %} {%- endfor %}
]; ];
var gws = [ var gws = [

View File

@ -163,11 +163,11 @@
<tbody> <tbody>
{%- for mac, value in gws.items() %} {%- for mac, value in gws.items() %}
<tr> <tr>
<td class="firstrow" data-order="{{ value["sort"] }}"><p style="margin:0"><a href="{{ url_for('router_list', q='selected:^%s$' % mac) }}">{{ gws_info[mac]["label"] }}</a></p> <td class="firstrow" data-order="{{ value["sort"] }}"><p style="margin:0"><a href="{{ url_for('router_list', q='selected:^%s$' % mac|int2shortmac) }}">{{ gws_info[mac]["label"] }}</a></p>
{%- if gws_info[mac]["gw"] %} {%- if gws_info[mac]["gw"] %}
<p style="margin:0;font-size:12px">{{ mac }} <p style="margin:0;font-size:12px">{{ mac|int2mac }}
{%- if gws_info[mac]["batmac"] %} {%- if gws_info[mac]["batmac"] %}
/ {{ gws_info[mac]["batmac"] }} / {{ gws_info[mac]["batmac"]|int2mac }}
{%- endif %} {%- endif %}
</p> </p>
{%- endif %} {%- endif %}
@ -176,7 +176,7 @@
<td class="danger" data-order="{{ (value["selected"]["offline"] or 0) + (value["others"]["offline"] or 0) }}"><span style="font-weight:bold">{{ value["selected"]["offline"] or 0 }}</span> / {{ value["others"]["offline"] or 0 }}</td> <td class="danger" data-order="{{ (value["selected"]["offline"] or 0) + (value["others"]["offline"] or 0) }}"><span style="font-weight:bold">{{ value["selected"]["offline"] or 0 }}</span> / {{ value["others"]["offline"] or 0 }}</td>
<td class="warning" data-order="{{ (value["selected"]["unknown"] or 0) + (value["others"]["unknown"] or 0) }}"><span style="font-weight:bold">{{ value["selected"]["unknown"] or 0 }}</span> / {{ value["others"]["unknown"] or 0 }}</td> <td class="warning" data-order="{{ (value["selected"]["unknown"] or 0) + (value["others"]["unknown"] or 0) }}"><span style="font-weight:bold">{{ value["selected"]["unknown"] or 0 }}</span> / {{ value["others"]["unknown"] or 0 }}</td>
<td class="active" data-order="{{ (value["selected"]|sumdict if value["selected"] else 0) + (value["others"]|sumdict if value["others"] else 0) }}"><span style="font-weight:bold">{{ gws_sum[mac]["routers"] if gws_sum[mac] else 0 }}</span> / {{ value["others"]|sumdict if value["others"] else 0 }}</td> <td class="active" data-order="{{ (value["selected"]|sumdict if value["selected"] else 0) + (value["others"]|sumdict if value["others"] else 0) }}"><span style="font-weight:bold">{{ gws_sum[mac]["routers"] if gws_sum[mac] else 0 }}</span> / {{ value["others"]|sumdict if value["others"] else 0 }}</td>
<td class="stats"><a href="{{ url_for('global_gwstatistics', selectgw='%s' % mac) }}">Stats</a></td> <td class="stats"><a href="{{ url_for('global_gwstatistics', selectgw='%s' % mac|int2shortmac) }}">Stats</a></td>
</tr> </tr>
{%- endfor %} {%- endfor %}
</tbody> </tbody>
@ -190,21 +190,21 @@
<div class="panel-heading">Gateway-Details</div> <div class="panel-heading">Gateway-Details</div>
<div class="panel-body"> <div class="panel-body">
<table class="table table-condensed"> <table class="table table-condensed">
<tr><th>Gateway</th><td>{{ gws_info[selectgw]["gw"] }}</td></tr> <tr><th>Gateway</th><td>{{ gws_info[selectgwint]["gw"] }}</td></tr>
<tr><th>Interface</th><td>{{ gws_info[selectgw]["gwif"] }}</td></tr> <tr><th>Interface</th><td>{{ gws_info[selectgwint]["gwif"] }}</td></tr>
<tr><th>MAC address</th><td>{{ selectgw }}</td></tr> <tr><th>MAC address</th><td>{{ selectgw }}</td></tr>
<tr><th>BatX interface</th><td>{{ gws_info[selectgw]["batX"] }}</td></tr> <tr><th>BatX interface</th><td>{{ gws_info[selectgwint]["batX"] }}</td></tr>
{%- if gws_info[selectgw]["ipv4"] %} {%- if gws_info[selectgwint]["ipv4"] %}
<tr><th>Internal IPv4</th><td>{{ gws_info[selectgw]["ipv4"] }}</td></tr> <tr><th>Internal IPv4</th><td>{{ gws_info[selectgwint]["ipv4"] }}</td></tr>
{%- endif %} {%- endif %}
{%- if gws_info[selectgw]["ipv6"] %} {%- if gws_info[selectgwint]["ipv6"] %}
<tr><th>Internal IPv6</th><td>{{ gws_info[selectgw]["ipv6"] }}</td></tr> <tr><th>Internal IPv6</th><td>{{ gws_info[selectgwint]["ipv6"] }}</td></tr>
{%- endif %} {%- endif %}
{%- if gws_info[selectgw]["dhcpstart"] %} {%- if gws_info[selectgwint]["dhcpstart"] %}
<tr><th>DHCP range</th><td>{{ gws_info[selectgw]["dhcpstart"] }} - {{ gws_info[selectgw]["dhcpend"] }}</td></tr> <tr><th>DHCP range</th><td>{{ gws_info[selectgwint]["dhcpstart"] }} - {{ gws_info[selectgwint]["dhcpend"] }}</td></tr>
{%- endif %} {%- endif %}
{%- if gws_info[selectgw]["stats_page"] %} {%- if gws_info[selectgwint]["stats_page"] %}
<tr><th>Stats page</th><td>{{ gws_info[selectgw]["stats_page"] }}</td></tr> <tr><th>Stats page</th><td>{{ gws_info[selectgwint]["stats_page"] }}</td></tr>
{%- endif %} {%- endif %}
{%- for a in gws_admin %} {%- for a in gws_admin %}
<tr><th>Admin</th><td>{{ a }}</td></tr> <tr><th>Admin</th><td>{{ a }}</td></tr>