def getConnectablePeers(self, need_num=5, ignore=[], allow_private=True): peers = self.peers.values() found = [] for peer in peers: if peer.key.endswith(":0"): continue # Not connectable if not peer.connection: continue # No connection if peer.key in ignore: continue # The requester has this peer if time.time() - peer.connection.last_recv_time > 60 * 60 * 2: # Last message more than 2 hours ago peer.connection = None # Cleanup: Dead connection continue if not allow_private and helper.isPrivateIp(peer.ip): continue found.append(peer) if len(found) >= need_num: break # Found requested number of peers if len(found) < need_num: # Return not that good peers found = [ peer for peer in peers if not peer.key.endswith(":0") and peer.key not in ignore and (allow_private or not helper.isPrivateIp(peer.ip)) ][0:need_num - len(found)] return found
def getConnectablePeers(self, need_num=5, ignore=[], allow_private=True): peers = self.peers.values() found = [] for peer in peers: if peer.key.endswith(":0"): continue # Not connectable if not peer.connection: continue # No connection if peer.key in ignore: continue # The requester has this peer if time.time() - peer.connection.last_recv_time > 60 * 60 * 2: # Last message more than 2 hours ago peer.connection = None # Cleanup: Dead connection continue if not allow_private and helper.isPrivateIp(peer.ip): continue found.append(peer) if len(found) >= need_num: break # Found requested number of peers if len(found) < need_num: # Return not that good peers found += [ peer for peer in peers if not peer.key.endswith(":0") and peer.key not in ignore and (allow_private or not helper.isPrivateIp(peer.ip)) ][0:need_num - len(found)] return found
def handleIncomingConnection(self, sock, addr): if config.offline: sock.close() return False ip, port = addr[0:2] ip = ip.lower() if ip.startswith("::ffff:"): # IPv6 to IPv4 mapping ip = ip.replace("::ffff:", "", 1) self.num_incoming += 1 if not self.had_external_incoming and not helper.isPrivateIp(ip): self.had_external_incoming = True # Connection flood protection if ip in self.ip_incoming and ip not in self.whitelist: self.ip_incoming[ip] += 1 if self.ip_incoming[ip] > 6: # Allow 6 in 1 minute from same ip self.log.debug("Connection flood detected from %s" % ip) time.sleep(30) sock.close() return False else: self.ip_incoming[ip] = 1 connection = Connection(self, ip, port, sock) self.connections.append(connection) if ip not in config.ip_local: self.ips[ip] = connection connection.handleIncomingConnection(sock)
def connect(self): self.log("Connecting...") self.type = "out" if self.ip.endswith(".onion"): if not self.server.tor_manager or not self.server.tor_manager.enabled: raise Exception("Can't connect to onion addresses, no Tor controller present") self.sock = self.server.tor_manager.createSocket(self.ip, self.port) elif config.tor == "always" and helper.isPrivateIp(self.ip) and self.ip not in config.ip_local: raise Exception("Can't connect to local IPs in Tor: always mode") else: self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if "TCP_NODELAY" in dir(socket): self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) self.sock.connect((self.ip, int(self.port))) # Implicit SSL if self.cert_pin: self.sock = CryptConnection.manager.wrapSocket(self.sock, "tls-rsa", cert_pin=self.cert_pin) self.sock.do_handshake() self.crypt = "tls-rsa" self.sock_wrapped = True # Detect protocol self.send({"cmd": "handshake", "req_id": 0, "params": self.getHandshakeInfo()}) event_connected = self.event_connected gevent.spawn(self.messageLoop) return event_connected.get() # Wait for handshake
def __init__(self, server, ip, port, sock=None, target_onion=None, is_tracker_connection=False): self.sock = sock self.ip = ip self.port = port self.cert_pin = None if "#" in ip: self.ip, self.cert_pin = ip.split("#") self.target_onion = target_onion # Requested onion adress self.id = server.last_connection_id server.last_connection_id += 1 self.protocol = "?" self.type = "?" if helper.isPrivateIp(self.ip) and self.ip not in config.ip_local: self.is_private_ip = True else: self.is_private_ip = False self.is_tracker_connection = is_tracker_connection self.server = server self.unpacker = None # Stream incoming socket messages here self.req_id = 0 # Last request id self.handshake = {} # Handshake info got from peer self.crypt = None # Connection encryption method self.sock_wrapped = False # Socket wrapped to encryption self.connected = False self.event_connected = gevent.event.AsyncResult( ) # Solves on handshake received self.closed = False # Stats self.start_time = time.time() self.last_recv_time = 0 self.last_message_time = 0 self.last_send_time = 0 self.last_sent_time = 0 self.incomplete_buff_recv = 0 self.bytes_recv = 0 self.bytes_sent = 0 self.last_ping_delay = None self.last_req_time = 0 self.last_cmd_sent = None self.last_cmd_recv = None self.bad_actions = 0 self.sites = 0 self.cpu_time = 0.0 self.send_lock = RLock() self.name = None self.updateName() self.waiting_requests = {} # Waiting sent requests self.waiting_streams = {} # Waiting response file streams
def connect(self): self.type = "out" if self.ip.endswith(".onion"): if not self.server.tor_manager or not self.server.tor_manager.enabled: raise Exception( "Can't connect to onion addresses, no Tor controller present" ) self.sock = self.server.tor_manager.createSocket( self.ip, self.port) elif config.tor == "always" and helper.isPrivateIp( self.ip) and self.ip not in config.ip_local: raise Exception("Can't connect to local IPs in Tor: always mode") elif config.trackers_proxy != "disable" and self.is_tracker_connection: if config.trackers_proxy == "tor": self.sock = self.server.tor_manager.createSocket( self.ip, self.port) else: from lib.PySocks import socks self.sock = socks.socksocket() proxy_ip, proxy_port = config.trackers_proxy.split(":") self.sock.set_proxy(socks.PROXY_TYPE_SOCKS5, proxy_ip, int(proxy_port)) else: self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if "TCP_NODELAY" in dir(socket): self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) timeout_before = self.sock.gettimeout() self.sock.settimeout(30) self.sock.connect((self.ip, int(self.port))) # Implicit SSL should_encrypt = not self.ip.endswith( ".onion" ) and self.ip not in self.server.broken_ssl_ips and self.ip not in config.ip_local if self.cert_pin: self.sock = CryptConnection.manager.wrapSocket( self.sock, "tls-rsa", cert_pin=self.cert_pin) self.sock.do_handshake() self.crypt = "tls-rsa" self.sock_wrapped = True elif should_encrypt and "tls-rsa" in CryptConnection.manager.crypt_supported: try: self.sock = CryptConnection.manager.wrapSocket( self.sock, "tls-rsa") self.sock.do_handshake() self.crypt = "tls-rsa" self.sock_wrapped = True except Exception, err: if not config.force_encryption: self.log( "Crypt connection error: %s, adding ip %s as broken ssl." % (err, self.ip)) self.server.broken_ssl_ips[self.ip] = True self.sock.close() self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect((self.ip, int(self.port)))
def sidebarRenderPeerStats(self, body, site): connected = len([ peer for peer in site.peers.values() if peer.connection and peer.connection.connected ]) connectable = len([ peer_id for peer_id in site.peers.keys() if not peer_id.endswith(":0") ]) onion = len( [peer_id for peer_id in site.peers.keys() if ".onion" in peer_id]) local = len([ peer for peer in site.peers.values() if helper.isPrivateIp(peer.ip) ]) peers_total = len(site.peers) # Add myself if site.settings["serving"]: peers_total += 1 if site.connection_server.port_opened: connectable += 1 if site.connection_server.tor_manager.start_onions: onion += 1 if peers_total: percent_connected = float(connected) / peers_total percent_connectable = float(connectable) / peers_total percent_onion = float(onion) / peers_total else: percent_connectable = percent_connected = percent_onion = 0 if local: local_html = _( u"<li class='color-yellow'><span>{_[Local]}:</span><b>{local}</b></li>" ) else: local_html = "" body.append( _(u""" <li> <label>{_[Peers]}</label> <ul class='graph'> <li style='width: 100%' class='total back-black' title="{_[Total peers]}"></li> <li style='width: {percent_connectable:.0%}' class='connectable back-blue' title='{_[Connectable peers]}'></li> <li style='width: {percent_onion:.0%}' class='connected back-purple' title='{_[Onion]}'></li> <li style='width: {percent_connected:.0%}' class='connected back-green' title='{_[Connected peers]}'></li> </ul> <ul class='graph-legend'> <li class='color-green'><span>{_[Connected]}:</span><b>{connected}</b></li> <li class='color-blue'><span>{_[Connectable]}:</span><b>{connectable}</b></li> <li class='color-purple'><span>{_[Onion]}:</span><b>{onion}</b></li> {local_html} <li class='color-black'><span>{_[Total]}:</span><b>{peers_total}</b></li> </ul> </li> """))
def sidebarRenderPeerStats(self, body, site): connected = len([peer for peer in site.peers.values() if peer.connection and peer.connection.connected]) connectable = len([peer_id for peer_id in site.peers.keys() if not peer_id.endswith(":0")]) onion = len([peer_id for peer_id in site.peers.keys() if ".onion" in peer_id]) local = len([peer for peer in site.peers.values() if helper.isPrivateIp(peer.ip)]) peers_total = len(site.peers) # Add myself if site.settings["serving"]: peers_total += 1 if site.connection_server.port_opened: connectable += 1 if site.connection_server.tor_manager.start_onions: onion += 1 if peers_total: percent_connected = float(connected) / peers_total percent_connectable = float(connectable) / peers_total percent_onion = float(onion) / peers_total else: percent_connectable = percent_connected = percent_onion = 0 if local: local_html = _(u"<li class='color-yellow'><span>{_[Local]}:</span><b>{local}</b></li>") else: local_html = "" peer_ips = [peer.key for peer in site.getConnectablePeers(20, allow_private=False)] peer_ips.sort(key=lambda peer_ip: ".onion:" in peer_ip) copy_link = "http://127.0.0.1:43110/%s/?zeronet_peers=%s" % ( site.content_manager.contents["content.json"].get("domain", site.address), ",".join(peer_ips) ) body.append(_(u""" <li> <label> {_[Peers]} <small class="label-right"><a href='{copy_link}' id='link-copypeers' class='link-right'>{_[Copy to clipboard]}</a></small> </label> <ul class='graph'> <li style='width: 100%' class='total back-black' title="{_[Total peers]}"></li> <li style='width: {percent_connectable:.0%}' class='connectable back-blue' title='{_[Connectable peers]}'></li> <li style='width: {percent_onion:.0%}' class='connected back-purple' title='{_[Onion]}'></li> <li style='width: {percent_connected:.0%}' class='connected back-green' title='{_[Connected peers]}'></li> </ul> <ul class='graph-legend'> <li class='color-green'><span>{_[Connected]}:</span><b>{connected}</b></li> <li class='color-blue'><span>{_[Connectable]}:</span><b>{connectable}</b></li> <li class='color-purple'><span>{_[Onion]}:</span><b>{onion}</b></li> {local_html} <li class='color-black'><span>{_[Total]}:</span><b>{peers_total}</b></li> </ul> </li> """))
def __init__(self, server, ip, port, sock=None, target_onion=None, is_tracker_connection=False): self.sock = sock self.ip = ip self.port = port self.cert_pin = None if "#" in ip: self.ip, self.cert_pin = ip.split("#") self.target_onion = target_onion # Requested onion adress self.id = server.last_connection_id server.last_connection_id += 1 self.protocol = "?" self.type = "?" if helper.isPrivateIp(self.ip) and self.ip not in config.ip_local: self.is_private_ip = True else: self.is_private_ip = False self.is_tracker_connection = is_tracker_connection self.server = server self.unpacker = None # Stream incoming socket messages here self.req_id = 0 # Last request id self.handshake = {} # Handshake info got from peer self.crypt = None # Connection encryption method self.sock_wrapped = False # Socket wrapped to encryption self.connected = False self.event_connected = gevent.event.AsyncResult() # Solves on handshake received self.closed = False # Stats self.start_time = time.time() self.handshake_time = 0 self.last_recv_time = 0 self.last_message_time = 0 self.last_send_time = 0 self.last_sent_time = 0 self.incomplete_buff_recv = 0 self.bytes_recv = 0 self.bytes_sent = 0 self.last_ping_delay = None self.last_req_time = 0 self.last_cmd_sent = None self.last_cmd_recv = None self.bad_actions = 0 self.sites = 0 self.cpu_time = 0.0 self.send_lock = RLock() self.name = None self.updateName() self.waiting_requests = {} # Waiting sent requests self.waiting_streams = {} # Waiting response file streams
def connect(self): self.type = "out" if self.ip.endswith(".onion"): if not self.server.tor_manager or not self.server.tor_manager.enabled: raise Exception("Can't connect to onion addresses, no Tor controller present") self.sock = self.server.tor_manager.createSocket(self.ip, self.port) elif config.tor == "always" and helper.isPrivateIp(self.ip) and self.ip not in config.ip_local: raise Exception("Can't connect to local IPs in Tor: always mode") elif config.trackers_proxy != "disable" and self.is_tracker_connection: if config.trackers_proxy == "tor": self.sock = self.server.tor_manager.createSocket(self.ip, self.port) else: from lib.PySocks import socks self.sock = socks.socksocket() proxy_ip, proxy_port = config.trackers_proxy.split(":") self.sock.set_proxy(socks.PROXY_TYPE_SOCKS5, proxy_ip, int(proxy_port)) else: self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if "TCP_NODELAY" in dir(socket): self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) timeout_before = self.sock.gettimeout() self.sock.settimeout(30) self.sock.connect((self.ip, int(self.port))) # Implicit SSL should_encrypt = not self.ip.endswith(".onion") and self.ip not in self.server.broken_ssl_ips and self.ip not in config.ip_local if self.cert_pin: self.sock = CryptConnection.manager.wrapSocket(self.sock, "tls-rsa", cert_pin=self.cert_pin) self.sock.do_handshake() self.crypt = "tls-rsa" self.sock_wrapped = True elif should_encrypt and "tls-rsa" in CryptConnection.manager.crypt_supported: try: self.sock = CryptConnection.manager.wrapSocket(self.sock, "tls-rsa") self.sock.do_handshake() self.crypt = "tls-rsa" self.sock_wrapped = True except Exception, err: if not config.force_encryption: self.log("Crypt connection error: %s, adding ip %s as broken ssl." % (err, self.ip)) self.server.broken_ssl_ips[self.ip] = True self.sock.close() self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect((self.ip, int(self.port)))
def sidebarRenderPeerStats(self, body, site): connected = len([peer for peer in site.peers.values() if peer.connection and peer.connection.connected]) connectable = len([peer_id for peer_id in site.peers.keys() if not peer_id.endswith(":0")]) onion = len([peer_id for peer_id in site.peers.keys() if ".onion" in peer_id]) local = len([peer for peer in site.peers.values() if helper.isPrivateIp(peer.ip)]) peers_total = len(site.peers) # Add myself if site.settings["serving"]: peers_total += 1 if site.connection_server.port_opened: connectable += 1 if site.connection_server.tor_manager.start_onions: onion += 1 if peers_total: percent_connected = float(connected) / peers_total percent_connectable = float(connectable) / peers_total percent_onion = float(onion) / peers_total else: percent_connectable = percent_connected = percent_onion = 0 if local: local_html = _(u"<li class='color-yellow'><span>{_[Local]}:</span><b>{local}</b></li>") else: local_html = "" body.append(_(u""" <li> <label>{_[Peers]}</label> <ul class='graph'> <li style='width: 100%' class='total back-black' title="{_[Total peers]}"></li> <li style='width: {percent_connectable:.0%}' class='connectable back-blue' title='{_[Connectable peers]}'></li> <li style='width: {percent_onion:.0%}' class='connected back-purple' title='{_[Onion]}'></li> <li style='width: {percent_connected:.0%}' class='connected back-green' title='{_[Connected peers]}'></li> </ul> <ul class='graph-legend'> <li class='color-green'><span>{_[Connected]}:</span><b>{connected}</b></li> <li class='color-blue'><span>{_[Connectable]}:</span><b>{connectable}</b></li> <li class='color-purple'><span>{_[Onion]}:</span><b>{onion}</b></li> {local_html} <li class='color-black'><span>{_[Total]}:</span><b>{peers_total}</b></li> </ul> </li> """))
def connect(self): self.type = "out" if self.ip_type == "onion": if not self.server.tor_manager or not self.server.tor_manager.enabled: raise Exception( "Can't connect to onion addresses, no Tor controller present" ) self.sock = self.server.tor_manager.createSocket( self.ip, self.port) elif config.tor == "always" and helper.isPrivateIp( self.ip) and self.ip not in config.ip_local: raise Exception("Can't connect to local IPs in Tor: always mode") elif config.trackers_proxy != "disable" and config.tor != "always" and self.is_tracker_connection: if config.trackers_proxy == "tor": self.sock = self.server.tor_manager.createSocket( self.ip, self.port) else: import socks self.sock = socks.socksocket() proxy_ip, proxy_port = config.trackers_proxy.split(":") self.sock.set_proxy(socks.PROXY_TYPE_SOCKS5, proxy_ip, int(proxy_port)) else: self.sock = self.createSocket() if "TCP_NODELAY" in dir(socket): self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) timeout_before = self.sock.gettimeout() self.sock.settimeout(30) if self.ip_type == "ipv6" and not hasattr(self.sock, "proxy"): sock_address = (self.ip, self.port, 1, 1) else: sock_address = (self.ip, self.port) self.sock.connect(sock_address) # Implicit SSL should_encrypt = not self.ip_type == "onion" and self.ip not in self.server.broken_ssl_ips and self.ip not in config.ip_local if self.cert_pin: self.sock = CryptConnection.manager.wrapSocket( self.sock, "tls-rsa", cert_pin=self.cert_pin) self.sock.do_handshake() self.crypt = "tls-rsa" self.sock_wrapped = True elif should_encrypt and "tls-rsa" in CryptConnection.manager.crypt_supported: try: self.sock = CryptConnection.manager.wrapSocket( self.sock, "tls-rsa") self.sock.do_handshake() self.crypt = "tls-rsa" self.sock_wrapped = True except Exception as err: if not config.force_encryption: self.log( "Crypt connection error, adding %s:%s as broken ssl. %s" % (self.ip, self.port, Debug.formatException(err))) self.server.broken_ssl_ips[self.ip] = True self.sock.close() self.crypt = None self.sock = self.createSocket() self.sock.settimeout(30) self.sock.connect(sock_address) # Detect protocol self.send({ "cmd": "handshake", "req_id": 0, "params": self.getHandshakeInfo() }) event_connected = self.event_connected gevent.spawn(self.messageLoop) connect_res = event_connected.get() # Wait for handshake self.sock.settimeout(timeout_before) return connect_res
def portCheck(self): if config.ip_external: for ip_external in config.ip_external: SiteManager.peer_blacklist.append((ip_external, self.port)) # Add myself to peer blacklist ip_external_types = set([helper.getIpType(ip) for ip in config.ip_external]) res = { "ipv4": "ipv4" in ip_external_types, "ipv6": "ipv6" in ip_external_types } self.ip_external_list = config.ip_external self.port_opened.update(res) self.log.info("Server port opened based on configuration ipv4: %s, ipv6: %s" % (res["ipv4"], res["ipv6"])) return res self.port_opened = {} if self.ui_server: self.ui_server.updateWebsocket() if "ipv6" in self.supported_ip_types: res_ipv6_thread = gevent.spawn(self.portchecker.portCheck, self.port, "ipv6") else: res_ipv6_thread = None res_ipv4 = self.portchecker.portCheck(self.port, "ipv4") if not res_ipv4["opened"]: if self.portchecker.portOpen(self.port): res_ipv4 = self.portchecker.portCheck(self.port, "ipv4") if res_ipv6_thread is None: res_ipv6 = {"ip": None, "opened": None} else: res_ipv6 = res_ipv6_thread.get() if res_ipv6["opened"] and not helper.getIpType(res_ipv6["ip"]) == "ipv6": self.log.info("Invalid IPv6 address from port check: %s" % res_ipv6["ip"]) res_ipv6["opened"] = False self.ip_external_list = [] for res_ip in [res_ipv4, res_ipv6]: if res_ip["ip"] and res_ip["ip"] not in self.ip_external_list: self.ip_external_list.append(res_ip["ip"]) SiteManager.peer_blacklist.append((res_ip["ip"], self.port)) self.log.info("Server port opened ipv4: %s, ipv6: %s" % (res_ipv4["opened"], res_ipv6["opened"])) res = {"ipv4": res_ipv4["opened"], "ipv6": res_ipv6["opened"]} # Add external IPs from local interfaces interface_ips = helper.getInterfaceIps("ipv4") if "ipv6" in self.supported_ip_types: interface_ips += helper.getInterfaceIps("ipv6") for ip in interface_ips: if not helper.isPrivateIp(ip) and ip not in self.ip_external_list: self.ip_external_list.append(ip) SiteManager.peer_blacklist.append((ip, self.port)) self.log.debug("External ip found on interfaces: %s" % ip) self.port_opened.update(res) if self.ui_server: self.ui_server.updateWebsocket() return res
def testIsPrivateIp(self): assert helper.isPrivateIp("192.168.1.1") assert not helper.isPrivateIp("1.1.1.1") assert helper.isPrivateIp("fe80::44f0:3d0:4e6:637c") assert not helper.isPrivateIp( "fca5:95d6:bfde:d902:8951:276e:1111:a22c") # cjdns
def testIsPrivateIp(self): assert helper.isPrivateIp("192.168.1.1") assert not helper.isPrivateIp("1.1.1.1")