def test_lan_learn(self): if onionrvalues.IS_QUBES: logger.info('Cannot run LAN tests on Qubes') return test_ip = '192.168.1.30' def multicast(): port = 1349 MULTICAST_TTL = 3 ips = '-'.join([test_ip]) + f'-{port}' sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, MULTICAST_TTL) sock.sendto(f"onionr-{ips}".encode('utf-8'), (MCAST_GRP, MCAST_PORT)) bettersleep.better_sleep(1) try: sock.shutdown(SHUT_RDWR) except OSError: pass sock.close() test_list = [test_ip] Thread(target=learn_services, daemon=True).start() bettersleep.better_sleep(3) multicast() self.assertIn(test_ip, test_list)
def test_block_list(self): block_list = BlockList() self.assertEqual(len(block_list.get()), 0) bl = insert('test') bettersleep.better_sleep(0.8) self.assertIn(bl, block_list.get()) bl2 = insert('test2') bettersleep.better_sleep(0.8) self.assertIn(bl2, block_list.get()) self.assertIn(bl, block_list.get())
def multicast(): port = 1349 MULTICAST_TTL = 3 ips = '-'.join([test_ip]) + f'-{port}' sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, MULTICAST_TTL) sock.sendto(f"onionr-{ips}".encode('utf-8'), (MCAST_GRP, MCAST_PORT)) bettersleep.better_sleep(1) try: sock.shutdown(SHUT_RDWR) except OSError: pass sock.close()
def advertise_service(specific_ips=None): # regarding socket.IP_MULTICAST_TTL # --------------------------------- # for all packets sent, after three hops on the network the packet will not # be re-sent/broadcast (see https://www.tldp.org/HOWTO/Multicast-HOWTO-6.html) MULTICAST_TTL = 3 ips = best_ip sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, MULTICAST_TTL) while True: sock.sendto(f"onionr-{ips}".encode('utf-8'), (MCAST_GRP, MCAST_PORT)) better_sleep(ANNOUNCE_LOOP_SLEEP)
def test_lan_broadcast(self): test_ip = '192.168.1.30' if onionrvalues.IS_QUBES: logger.info('Cannot run LAN tests on Qubes') return def multicast(): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if IS_ALL_GROUPS: # on this port, receives ALL multicast groups sock.bind(('', MCAST_PORT)) else: # on this port, listen ONLY to MCAST_GRP sock.bind((MCAST_GRP, MCAST_PORT)) mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY) sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) service_ips = sock.recv(200).decode('utf-8') if not service_ips: raise ValueError self.assertIn('onionr', service_ips) self.assertEqual( len( set( set(service_ips.replace('onionr', '').split('-')) ^ set(lan_ips))), 1) for x in set( set(service_ips.replace('onionr', '').split('-')) ^ set(lan_ips)): self.assertEqual('', x) try: sock.shutdown(SHUT_RDWR) except OSError: pass sock.close() test_list = [test_ip] Thread(target=advertise_service, daemon=True).start() bettersleep.better_sleep(1) multicast()
def statistics_reporter(shared_state): server = config.get('statistics.server', '') if not config.get('statistics.i_dont_want_privacy', False) or \ not server: return def compile_data(): return { 'time': epoch.get_epoch(), 'adders': get_transports(), 'peers': shared_state.get_by_string('DeadSimpleKV').get('onlinePeers') } while True: better_sleep(5) data = compile_data() basicrequests.do_post_request(f'http://{server}/sendstats/' + get_transports()[0], data=json.dumps(data))
def daemon(): """Start Onionr's primary threads for communicator, API server, node, and LAN.""" def _handle_sig_term(signum, frame): pid = str(os.getpid()) main_pid = localcommand.local_command('/getpid') #logger.info(main_pid, terminal=True) if main_pid and main_pid == pid: logger.info( f"Received sigterm, shutting down gracefully. PID: {pid}", terminal=True) localcommand.local_command('/shutdownclean') else: logger.info( f"Recieved sigterm in child process or fork, exiting. PID: {pid}") sys.exit(0) signal.signal(signal.SIGTERM, _handle_sig_term) # Determine if Onionr is in offline mode. # When offline, Onionr can only use LAN and disk transport offline_mode = config.get('general.offline_mode', False) if not hastor.has_tor(): offline_mode = True logger.error("Tor is not present in system path or Onionr directory", terminal=True) # Create shared objects shared_state = toomanyobjs.TooMany() # Add DeadSimpleKV for quasi-global variables (ephemeral key-value) shared_state.get(DeadSimpleKV) # Initialize the quasi-global variables setup_kv(shared_state.get(DeadSimpleKV)) shared_state.get(daemoneventsapi.DaemonEventsBP) Thread(target=shared_state.get(apiservers.ClientAPI).start, daemon=True, name='client HTTP API').start() if not offline_mode: Thread(target=shared_state.get(apiservers.PublicAPI).start, daemon=True, name='public HTTP API').start() # Init run time tester # (ensures Onionr is running right, for testing purposes) # Run time tests are not normally run shared_state.get(runtests.OnionrRunTestManager) # Create singleton shared_state.get(serializeddata.SerializedData) shared_state.share_object() # share the parent object to the threads show_logo() # since we randomize loopback API server hostname to protect against attacks, # we have to wait for it to become set apiHost = '' if not offline_mode: apiHost = get_api_host_until_available() net = NetController(config.get('client.public.port', 59497), apiServerIP=apiHost) shared_state.add(net) shared_state.get(onionrstatistics.tor.TorStats) security_level = config.get('general.security_level', 1) use_existing_tor = config.get('tor.use_existing_tor', False) if not offline_mode: # we need to setup tor for use _setup_online_mode(use_existing_tor, net, security_level) _show_info_messages() logger.info( "Onionr daemon is running under " + str(os.getpid()), terminal=True) events.event('init', threaded=False) events.event('daemon_start') if config.get('transports.lan', True): if not onionrvalues.IS_QUBES: Thread(target=LANServer(shared_state).start_server, daemon=True).start() LANManager(shared_state).start() else: logger.warn('LAN not supported on Qubes', terminal=True) if config.get('transports.sneakernet', True): Thread(target=sneakernet_import_thread, daemon=True).start() Thread(target=statistics_reporter, args=[shared_state], daemon=True).start() shared_state.get(DeadSimpleKV).put( 'proxyPort', net.socksPort) spawn_client_threads(shared_state) clean_blocks_not_meeting_pow(shared_state) communicator.startCommunicator(shared_state) clean_ephemeral_services() if not offline_mode and not use_existing_tor: net.killTor() else: try: os.remove(filepaths.tor_hs_address_file) except FileNotFoundError: pass better_sleep(5) cleanup.delete_run_files() if security_level >= 2: filenuke.nuke.clean_tree(identifyhome.identify_home())
def _show_lan_bind(port): better_sleep(1) if self.server.started and port == self.server.server_port: logger.info(f'Serving to LAN on {self.host}:{self.port}', terminal=True)
def daemon(): """Start Onionr's primary threads for communicator, API server, node, and LAN.""" # Determine if Onionr is in offline mode. # When offline, Onionr can only use LAN and disk transport offline_mode = config.get('general.offline_mode', False) if not hastor.has_tor(): offline_mode = True logger.error("Tor is not present in system path or Onionr directory", terminal=True) # remove runcheck if it exists if os.path.isfile(filepaths.run_check_file): logger.debug('Runcheck file found on daemon start, deleting.') os.remove(filepaths.run_check_file) # Create shared objects shared_state = toomanyobjs.TooMany() # Add DeadSimpleKV for quasi-global variables (ephemeral key-value) shared_state.get(DeadSimpleKV) # Initialize the quasi-global variables setup_kv(shared_state.get(DeadSimpleKV)) spawn_client_threads(shared_state) shared_state.get(daemoneventsapi.DaemonEventsBP) Thread(target=shared_state.get(apiservers.ClientAPI).start, daemon=True, name='client HTTP API').start() if not offline_mode: Thread(target=shared_state.get(apiservers.PublicAPI).start, daemon=True, name='public HTTP API').start() # Init run time tester # (ensures Onionr is running right, for testing purposes) # Run time tests are not normally run shared_state.get(runtests.OnionrRunTestManager) # Create singleton shared_state.get(serializeddata.SerializedData) shared_state.share_object() # share the parent object to the threads show_logo() # since we randomize loopback API server hostname to protect against attacks, # we have to wait for it to become set apiHost = '' if not offline_mode: apiHost = get_api_host_until_available() net = NetController(config.get('client.public.port', 59497), apiServerIP=apiHost) shared_state.add(net) shared_state.get(onionrstatistics.tor.TorStats) security_level = config.get('general.security_level', 1) use_existing_tor = config.get('tor.use_existing_tor', False) if not offline_mode: # we need to setup tor for use _setup_online_mode(use_existing_tor, net, security_level) _show_info_messages() events.event('init', threaded=False) events.event('daemon_start') if config.get('transports.lan', True): Thread(target=LANServer(shared_state).start_server, daemon=True).start() LANManager(shared_state).start() if config.get('transports.sneakernet', True): Thread(target=sneakernet_import_thread, daemon=True).start() Thread(target=statistics_reporter, args=[shared_state], daemon=True).start() communicator.startCommunicator(shared_state) clean_ephemeral_services() if not offline_mode and not use_existing_tor: net.killTor() else: try: os.remove(filepaths.tor_hs_address_file) except FileNotFoundError: pass better_sleep(5) cleanup.delete_run_files() if security_level >= 2: filenuke.nuke.clean_tree(identifyhome.identify_home())