2015-11-21 11:52:48 +00:00
|
|
|
#!/usr/bin/env python3
|
2015-11-21 13:47:51 +00:00
|
|
|
# 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
|
2015-11-21 12:28:58 +00:00
|
|
|
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
|
2015-11-21 12:28:58 +00:00
|
|
|
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
|
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
|
|
|
|
2015-11-21 12:28:58 +00:00
|
|
|
import queue
|
|
|
|
import threading
|
2014-06-02 20:22:37 +00:00
|
|
|
|
2015-11-21 11:52:48 +00:00
|
|
|
def main():
|
|
|
|
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
|
|
|
|
2015-11-21 12:28:58 +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:
|
2015-11-21 12:28:58 +00:00
|
|
|
get_peer_queue.put(k)
|
2015-07-26 17:08:35 +00:00
|
|
|
|
2015-11-21 12:28:58 +00:00
|
|
|
for i in range(8):
|
2015-11-21 13:12:23 +00:00
|
|
|
t = threading.Thread(target=worker, args=[nodes, get_peer_queue, result_queue])
|
|
|
|
t.daemon = True
|
|
|
|
t.start()
|
2014-05-28 16:48:46 +00:00
|
|
|
|
2015-11-21 12:28:58 +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)
|
2014-05-30 14:34:00 +00:00
|
|
|
|
2015-11-21 11:52:48 +00:00
|
|
|
send_graph(nodes, edges)
|
|
|
|
sys.exit(0)
|
2014-05-30 14:34:00 +00:00
|
|
|
|
2015-11-21 12:28:58 +00:00
|
|
|
def worker(nodes, get_peer_queue, result):
|
|
|
|
con = connect()
|
|
|
|
|
|
|
|
while True:
|
|
|
|
try:
|
|
|
|
k = get_peer_queue.get_nowait()
|
|
|
|
except queue.Empty:
|
|
|
|
return
|
|
|
|
|
|
|
|
node = nodes[k]
|
|
|
|
print('fetch', node)
|
|
|
|
node_ip = node['ip']
|
|
|
|
|
|
|
|
peers = get_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:
|
2015-11-21 13:49:29 +00:00
|
|
|
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
|
|
|
print(admin_tools.whoami(con)['IP'])
|
|
|
|
return con
|
2014-05-28 16:48:46 +00:00
|
|
|
|
2015-11-21 11:52:48 +00:00
|
|
|
except:
|
|
|
|
print('Failed!')
|
|
|
|
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
|
|
|
|
|
|
|
|
2015-11-21 11:52:48 +00:00
|
|
|
def get_peers(con, path):
|
|
|
|
peers = set()
|
2014-05-28 16:48:46 +00:00
|
|
|
|
2015-11-21 11:52:48 +00:00
|
|
|
i = 1
|
2015-11-21 12:28:58 +00:00
|
|
|
while i < 3:
|
2015-11-21 11:52:48 +00:00
|
|
|
res = con.RouterModule_getPeers(path)
|
2014-05-28 16:48:46 +00:00
|
|
|
|
2015-11-21 11:52:48 +00:00
|
|
|
if ('result' in res and res['result'] == 'timeout') or \
|
|
|
|
('error' in res and res['error'] != 'none'):
|
|
|
|
failure = ''
|
|
|
|
if 'error' in res:
|
|
|
|
failure = res['error']
|
|
|
|
if 'result' in res:
|
|
|
|
if len(failure) != 0:
|
|
|
|
failure += '/'
|
|
|
|
failure += res['result']
|
2014-05-28 16:48:46 +00:00
|
|
|
|
2015-11-21 11:52:48 +00:00
|
|
|
print('get_peers: getPeers failed with {:s} on {:s}, trying again. {:d} tries remaining.'
|
2015-11-21 12:37:55 +00:00
|
|
|
.format(failure, path, 2 - i))
|
2015-11-21 11:52:48 +00:00
|
|
|
i += 1
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
break
|
2014-05-28 16:48:46 +00:00
|
|
|
|
2015-11-21 11:52:48 +00:00
|
|
|
if 'result' not in res or res['result'] != 'peers':
|
|
|
|
print('get_peers: failed too many times, skipping.')
|
|
|
|
print(res)
|
|
|
|
return peers
|
2014-05-28 16:48:46 +00:00
|
|
|
|
2015-11-21 11:52:48 +00:00
|
|
|
for peer in res['peers']:
|
|
|
|
key = peer.split('.', 5)[-1]
|
|
|
|
peers |= {key}
|
2014-05-28 16:48:46 +00:00
|
|
|
|
2015-11-21 11:52:48 +00:00
|
|
|
return peers
|
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
|
|
|
|
2015-11-21 11:52:48 +00:00
|
|
|
if node_ip > peer_ip:
|
|
|
|
A = node_ip
|
|
|
|
B = peer_ip
|
|
|
|
else:
|
|
|
|
A = peer_ip
|
|
|
|
B = node_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
|
|
|
|
2015-11-21 13:12:23 +00:00
|
|
|
if not([True for edge in edges[A] if edge['b'] == B]):
|
2015-11-21 11:52:48 +00:00
|
|
|
edges[A] += [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
|
|
|
|
2015-11-21 12:28:58 +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
|
|
|
|
2015-11-21 12:37:55 +00:00
|
|
|
if r.content == 'OK':
|
2015-11-21 11:52:48 +00:00
|
|
|
print('Done!')
|
|
|
|
else:
|
2015-11-21 13:49:40 +00:00
|
|
|
print('Error: {: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()
|