def doLog(self, message): """ Process a log line from cjdns to see if it indicates that a peer we are responsible for is unresponsive. """ logging.debug(message) # Short-circuit messages that start with the wrong l;etter and can't # possibly match. if message[0] != 'P': return # Test plausible messages against the regex p = IS_UNRESPONSIVE.match(message) # If they don't match, ignore them. if not p: return # Otherwise, get the key of the unresponsive node from the regex match # group. downKey = p.group(1) # And get the nodfe for that key node = self.nodes.get(downKey, None) if not node: # Complain we aren't responsible for that node. logging.debug("Unmonitored neighbor {} is down".format( PublicToIp6_convert(downKey))) return # Otherwise, announce we are doing our job. logging.warning("Monitored neighbor {} is down.".format( PublicToIp6_convert(downKey))) # If we are responsible for it, register it as unresponsive. self.unresponsive[downKey] = node # Go get its address and try reconnecting. self.lookup(node)
def makeGraph(): import cjdnsadmin.adminTools as admin import networkx as nx from cjdnsadmin.publicToIp6 import PublicToIp6_convert from collections import deque cjdns = admin.connect() root = admin.whoami(cjdns) rootIP = root['IP'] G = nx.Graph() G.add_node(rootIP[-4:], ip=rootIP) nodes = deque() nodes.append(rootIP) while len(nodes) != 0: parentIP = nodes.popleft() resp = cjdns.NodeStore_nodeForAddr(parentIP) numLinks = 0 if b'result' in resp: link = resp[b'result'] if b'linkCount' in link: numLinks = int(resp[b'result'][b'linkCount']) G.nodes[parentIP[-4:]]['version'] = resp[b'result'][ b'protocolVersion'] for i in range(0, numLinks): resp = cjdns.NodeStore_getLink(i, parent=parentIP) childLink = resp[b'result'] if not childLink: continue childAddr = admin.parseAddr(childLink[b'child']) childIP = PublicToIp6_convert(childAddr[b'publicKey']) # Check to see if its one hop away from parent node if childLink[b'isOneHop'] != 1: continue # If its a new node then we want to follow it if not childIP[-4:] in G.nodes(): G.add_node(childIP[-4:], ip=childIP) G.nodes[childIP[-4:]]['version'] = 0 nodes.append(childIP) # If there is not a link between the nodes we should put one there if (not childIP[-4:] in G[parentIP[-4:]]): G.add_edge(parentIP[-4:], childIP[-4:]) return G
def lookup(self, node): """ Look up the current IP address for the given Node object, and tell the cjdns router to try to connect to it. """ try: # Use AF_INET here to make sure we don't get an IPv6 address and try # to connect to it when the cjdns UDPInterface is using only IPv4. # TODO: Make cjdns bind its UDPInterface to IPv6 as well as IPv4. for info in socket.getaddrinfo(node.host, node.port, socket.AF_INET, socket.SOCK_DGRAM): # For every IP address the node has in DNS, with the port we # wanted attached... # Save the address we get in a field in the node. sockaddr = info[-1] node.lastAddr = sockaddr # Grab the IP:port string sockaddr = sockaddr[0] + ":" + str(sockaddr[1]) # Announce we are going to connect logging.info("Connecting to {} at {}".format( PublicToIp6_convert(node.key), sockaddr)) # Tell CJDNS to begin a UDPInterface connection to the given # IP:port, with the given public key and password. Always use # the 0th UDPInterface, which is the default. reply = self.cjdns.UDPInterface_beginConnection( password=node.password, publicKey=node.key, address=sockaddr) if reply["error"] != "none": # The router didn't like our request. Complain. logging.error( "Router refuses to connect to remote peer. {}".format( reply["error"])) # Maybe try the next address? break # Mark this node as no longer unresponsive try: del self.unresponsive[node.key] except KeyError: pass # Mark this node as no longer unresolved try: del self.unresolved[node.key] except KeyError: pass # Don't try any more addresses. Stop after the first. return except socket.gaierror as e: if IS_TRANSIENT_HOSTNAME.match(node.host): logging.info( "Transient name {} is currently not resolvable.".format( node.host)) self.unresolved[node.key] = node # return and try this node later again return else: # The lookup failed at the OS level. Did we put in a bad hostname? logging.error("Could not resolve DNS name {}: {}".format( node.host, e)) # If we get here, we found no addresses that worked. logging.error("No working addresses found for node {}".format( PublicToIp6_convert(node.key)))