def _arp_scan_thread_helper(self):

        while True:

            for ip in utils.get_network_ip_range():

                time.sleep(0.05)

                arp_pkt = sc.Ether(dst="ff:ff:ff:ff:ff:ff") / \
                    sc.ARP(pdst=ip, hwdst="ff:ff:ff:ff:ff:ff")
                sc.sendp(arp_pkt, verbose=0)

                with self._lock:
                    if not self._active:
                        return
    def _arp_scan_thread_helper(self):

        fast_scan_start_ts = None

        while True:

            if not self._host_state.is_inspecting():
                time.sleep(1)
                continue

            for ip in utils.get_network_ip_range():

                sleep_time = 1

                # Whether we should scan fast or slow
                with self._host_state.lock:
                    fast_arp_scan = self._host_state.fast_arp_scan

                # If fast scan, we do it for at most 5 mins
                if fast_arp_scan:
                    sleep_time = 0.1
                    if fast_scan_start_ts is None:
                        fast_scan_start_ts = time.time()
                    else:
                        if time.time() - fast_scan_start_ts > 300:
                            fast_scan_start_ts = None
                            sleep_time = 1
                            with self._host_state.lock:
                                self._host_state.fast_arp_scan = False

                time.sleep(sleep_time)

                arp_pkt = sc.Ether(dst="ff:ff:ff:ff:ff:ff") / \
                    sc.ARP(pdst=ip, hwdst="ff:ff:ff:ff:ff:ff")
                sc.sendp(arp_pkt, verbose=0)

                with self._lock:
                    if not self._active:
                        return
def main():
    sc.load_layer("http")
    # The whole process should be run as root.
    try:
        is_admin = os.getuid() == 0
    except AttributeError:
        is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0

    if not is_admin:
        sys.stderr.write('Please run as root.\n')
        sys.exit(1)

    # Check for Windows
    if utils.get_os() == 'windows':

        # Check Npcap installation
        npcap_path = os.path.join(os.environ['WINDIR'], 'System32', 'Npcap')
        if not os.path.exists(npcap_path):
            sys.stderr.write(
                "IoT Inspector cannot run without installing Npcap.\n")
            sys.stderr.write("For details, visit " +
                             server_config.NPCAP_ERROR_URL)
            utils.open_browser_on_windows(server_config.NPCAP_ERROR_URL)
            sys.exit(1)

        # Check presence of multiple interfaces (e.g., VPN)
        if len(utils.get_network_ip_range()) == 0:
            sys.stderr.write(
                "IoT Inspector cannot run with multiple network interfaces running.\n"
            )
            sys.stderr.write("For details, visit " +
                             server_config.NETMASK_ERROR_URL)
            utils.open_browser_on_windows(server_config.NETMASK_ERROR_URL)
            sys.exit(1)

    utils.log('[Main] Terminating existing processes.')
    if not kill_existing_inspector():
        utils.log('[Main] Unable to end existing process. Exiting.')
        return

    utils.log('[Main] Starting inspector.')
    inspector.enable_ip_forwarding()

    # We don't wrap the function below in safe_run because, well, if it crashes,
    # it crashes.
    host_state = inspector.start()

    # Waiting for termination
    while True:
        with host_state.lock:
            if host_state.quit:
                break
        try:
            time.sleep(2)
        except KeyboardInterrupt:
            print('')
            break

    utils.log('[Main] Restoring ARP...')

    with host_state.lock:
        host_state.spoof_arp = False

    for t in range(10):
        print('Cleaning up ({})...'.format(10 - t))
        time.sleep(1)

    inspector.disable_ip_forwarding()

    utils.log('[Main] Quit.')

    print('\n' * 100)
    print("""
        Princeton IoT Inspector has terminated.

        Feel free to close this window.

    """)

    # Remove PID file
    try:
        os.remove(get_pid_file())
    except Exception:
        pass