5
0
mirror of https://github.com/cwinfo/yggdrasil-map synced 2024-09-19 00:59:35 +00:00
yggdrasil-map/scripts/sendGraph.py

259 lines
6.3 KiB
Python
Raw Permalink Normal View History

2015-11-21 11:52:48 +00:00
#!/usr/bin/env python3
# Based on Kyrias' sendGraph script. Requires Python 3, requests and cjdns.
2015-11-21 13:29:42 +00:00
# You can install them using pip: pip3 install cjdns requests
2014-05-28 16:48:46 +00:00
###############################################################################
# CONFIG
# URL where data is sent
2015-11-21 13:29:42 +00:00
# www.fc00.org for clearnet access
2015-11-21 11:52:48 +00:00
# h.fc00.org for hyperboria
2015-07-26 17:08:35 +00:00
# [fc53:dcc5:e89d:9082:4097:6622:5e82:c654] for DNS-less access
url = 'http://www.fc00.org/sendGraph'
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
# update your email address, so I can contact you in case something goes wrong
your_mail = 'your@email.here'
2014-05-28 16:48:46 +00:00
# ----------------------
# RPC connection details
# ----------------------
# If this is set to True connection details will be loaded from ~/.cjdnsadmin
cjdns_use_default = True
2014-06-02 20:22:37 +00:00
# otherwise these are used.
2015-11-21 11:52:48 +00:00
cjdns_ip = '127.0.0.1'
cjdns_port = 11234
cjdns_password = 'NONE'
2014-05-28 16:48:46 +00:00
###############################################################################
2015-07-30 16:59:30 +00:00
import sys
2014-06-02 20:22:37 +00:00
import traceback
2014-05-28 16:48:46 +00:00
import json
import argparse
2014-06-02 20:22:37 +00:00
2015-11-21 11:52:48 +00:00
import requests
2014-06-02 20:22:37 +00:00
2015-11-21 11:52:48 +00:00
import cjdns
from cjdns import key_utils
from cjdns import admin_tools
2014-06-02 20:22:37 +00:00
import queue
import threading
2014-06-02 20:22:37 +00:00
2015-11-21 11:52:48 +00:00
def main():
parser = argparse.ArgumentParser(description='Submit nodes and links to fc00')
parser.add_argument('-v', '--verbose', help='increase output verbosity',
dest='verbose', action='store_true')
parser.set_defaults(verbose=False)
args = parser.parse_args()
2015-11-21 11:52:48 +00:00
con = connect()
2014-06-02 20:22:37 +00:00
2015-11-21 11:52:48 +00:00
nodes = dump_node_store(con)
edges = {}
2014-05-28 16:48:46 +00:00
get_peer_queue = queue.Queue(0)
result_queue = queue.Queue(0)
2015-11-21 11:52:48 +00:00
for k in nodes:
get_peer_queue.put(k)
2015-07-26 17:08:35 +00:00
for i in range(8):
t = threading.Thread(target=worker, args=[nodes, get_peer_queue, result_queue,
args.verbose])
2015-11-21 13:12:23 +00:00
t.daemon = True
t.start()
2014-05-28 16:48:46 +00:00
for i in range(len(nodes)):
peers, node_ip = result_queue.get()
2015-11-21 11:52:48 +00:00
get_edges_for_peers(edges, peers, node_ip)
2015-11-21 11:52:48 +00:00
send_graph(nodes, edges)
sys.exit(0)
def worker(nodes, get_peer_queue, result, verbose=False):
con = connect()
while True:
try:
k = get_peer_queue.get_nowait()
except queue.Empty:
return
node = nodes[k]
if verbose:
print('fetch', node)
node_ip = node['ip']
peers = get_all_peers(con, node['path'])
result.put((peers, node_ip))
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
def connect():
try:
if cjdns_use_default:
print('Connecting using default or ~/.cjdnsadmin credentials...')
con = cjdns.connectWithAdminInfo()
else:
print('Connecting to port {:d}...'.format(cjdns_port))
2015-11-21 11:52:48 +00:00
con = cjdns.connect(cjdns_ip, cjdns_port, cjdns_password)
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
return con
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
except:
print('Connection failed!')
2015-11-21 11:52:48 +00:00
print(traceback.format_exc())
sys.exit(1)
2014-06-02 20:22:37 +00:00
2015-11-21 11:52:48 +00:00
def dump_node_store(con):
nodes = dict()
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
i = 0
while True:
res = con.NodeStore_dumpTable(i)
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
if not 'routingTable' in res:
break
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
for n in res['routingTable']:
if not all(key in n for key in ('addr', 'path', 'ip')):
continue
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
ip = n['ip']
path = n['path']
addr = n['addr']
version = None
if 'version' in n:
version = n['version']
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
nodes[ip] = {'ip': ip, 'path': path, 'addr': addr, 'version': version}
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
if not 'more' in res or res['more'] != 1:
break
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
i += 1
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
return nodes
2014-05-28 16:48:46 +00:00
def get_peers(con, path, nearbyPath=''):
formatted_path = path
if nearbyPath:
formatted_path = '{:s} (nearby {:s})'.format(path, nearbyPath)
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
i = 1
2015-11-30 21:25:23 +00:00
retry = 2
while i < retry + 1:
if nearbyPath:
res = con.RouterModule_getPeers(path, nearbyPath=nearbyPath)
2015-11-21 11:52:48 +00:00
else:
res = con.RouterModule_getPeers(path)
2014-05-28 16:48:46 +00:00
if res['error'] == 'not_found':
print('get_peers: node with path {:s} not found, skipping.'
.format(formatted_path))
return []
elif res['error'] != 'none':
print('get_peers: failed with error `{:s}` on {:s}, trying again. {:d} tries remaining.'
2015-11-30 21:25:23 +00:00
.format(res['error'], formatted_path, retry-i))
elif res['result'] == 'timeout':
print('get_peers: timed out on {:s}, trying again. {:d} tries remaining.'
2015-11-30 21:25:23 +00:00
.format(formatted_path, retry-i))
else:
return res['peers']
i += 1
print('get_peers: failed on final try, skipping {:s}'
.format(formatted_path))
return []
def get_all_peers(con, path):
peers = set()
keys = set()
res = get_peers(con, path)
peers.update(res)
if not res:
return keys
last_peer = res[-1]
2015-11-30 21:25:23 +00:00
checked_paths = set()
while len(res) > 1:
last_path = (last_peer.split('.', 1)[1]
.rsplit('.', 2)[0])
2015-11-30 21:25:23 +00:00
if last_path in checked_paths:
break
else:
checked_paths.add(last_path)
res = get_peers(con, path, last_path)
if res:
last_peer = res[-1]
2015-11-30 21:25:23 +00:00
else:
break
peers.update(res)
2014-05-28 16:48:46 +00:00
for peer in peers:
2015-11-21 11:52:48 +00:00
key = peer.split('.', 5)[-1]
keys |= {key}
2014-05-28 16:48:46 +00:00
return keys
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
def get_edges_for_peers(edges, peers, node_ip):
for peer_key in peers:
peer_ip = key_utils.to_ipv6(peer_key)
2014-05-28 16:48:46 +00:00
2016-08-21 09:21:27 +00:00
A = max(node_ip, peer_ip)
B = min(node_ip, peer_ip)
2014-05-28 16:48:46 +00:00
2015-11-21 13:12:23 +00:00
edge = { 'a': A,
'b': B }
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
if A not in edges:
edges[A] = []
2014-05-28 16:48:46 +00:00
2016-08-21 09:21:27 +00:00
if not any(edge['b'] == B for edge in edges[A]):
edges[A].append(edge)
2014-05-28 16:48:46 +00:00
2015-07-26 17:08:35 +00:00
2015-11-21 11:52:48 +00:00
def send_graph(nodes, edges):
graph = {
'nodes': [],
'edges': [edge for sublist in edges.values()
for edge in sublist],
}
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
for node in nodes.values():
graph['nodes'].append({
'ip': node['ip'],
'version': node['version'],
})
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
print('Nodes: {:d}\nEdges: {:d}\n'.format(len(nodes), len(edges)))
2014-05-28 16:48:46 +00:00
2015-11-21 11:52:48 +00:00
json_graph = json.dumps(graph)
print('Sending data to {:s}...'.format(url))
2014-05-28 16:48:46 +00:00
payload = {'data': json_graph, 'mail': your_mail, 'version': 2}
2015-11-21 11:52:48 +00:00
r = requests.post(url, data=payload)
2014-05-28 16:48:46 +00:00
if r.text == 'OK':
2015-11-21 11:52:48 +00:00
print('Done!')
else:
print('{:s}'.format(r.text))
2014-05-28 16:48:46 +00:00
2014-06-04 18:41:33 +00:00
if __name__ == '__main__':
2015-11-21 11:52:48 +00:00
main()