def init_reply_doublecheck(self, pkt):
        """Ask the network who has each IP address. Does more than one host respond?"""
        print "Initiating doublecheck. Asking who has each IP address..."
        self.reply_doublecheck_dict = {}
        ips = self.cd.mac_of.keys()
        # sanity
        if len(ips) < 2: 
            return
        for ip in ips:
            if self.network is None:
                print "self.network is None, will error out..."

            # assemble ARP request params
            xswitch = pkt["switch"]
            xinport = pkt["inport"]
            # find valid IP address other than destination IP address
            srcip   = ips[0] if ips[0] != ip else ips[1] 
            srcmac  = self.cd.get_mac_of(srcip)
            dstmac  = "ff:ff:ff:ff:ff:ff"
            dstip   = ip

            # send out each physical port
            self.query.register_callback(self.log_reply_doublecheck)
            for loc in self.network.topology.egress_locations():
                switch  = loc.switch
                outport = loc.port_no
                send_arp(REQUEST,self.network,switch,outport,srcip,srcmac,dstip,dstmac)
           
        # in one second, check
        self.check_thread = threading.Thread(target=self.check_reply_doublecheck, args=(pkt['srcip'],))
        self.check_thread.daemon = True
        self.check_thread.start()
        return
    def test_promiscuity(self): 
        """Test if each host responds to ARP request sent to invalid MAC"""
        while True:
            INTERVAL = 10
            time.sleep(INTERVAL)
            print "Conducting promiscuity check..."
            now = time.time()

            # prepare to catch promiscuous hosts
            # to do this, we will send an ARP packet from a made up host to
            # each known host that has an INCORRECT dstmac address. If
            # the host responds, we know that it is listening on traffic that
            # is not intended for it, i.e. it is promiscuous.
            # ref. Sahai 01 "Detection of Promiscuous Nodes Using ARP Packets"
            wrong_mac = 'ff:ff:ff:ff:ff:fe'
            ips = self.cd.mac_of.keys() 
            # need at least 2 ips known to do this test
            if len(ips) < 2:
                print "Done."
                continue
            # pick random, unlikely mac
            key_mac = "77:77:77:77:77:77"
            self.policy = if_(match(dstmac=EthAddr(key_mac)), self.query, flood())

            # send out each physical port
            for loc in self.network.topology.egress_locations():
                switch  = loc.switch
                outport = loc.port_no
                dstmac = self.cd.get_port_to_mac(switch, outport)
                if not dstmac: 
                    # no mac associated with this port
                    continue
                dstip = next((k for k, v in self.cd.mac_of.items() if v == dstmac), None)
                if not dstip:
                    # no ip associated with this mac
                    continue

                # find valid IP address other than destination IP address
                key_ip = ips[0] if ips[0] != dstip else ips[1] 

                send_arp(REQUEST,self.network,switch,outport, key_ip, key_mac, dstip, wrong_mac)
    
            # wait for test to complete and revert policy
            time.sleep(1)
            self.policy = flood()
            print "Done."
    def init_request_doublecheck(self, pkt):
        """Send ARP request to suspicious host."""

        # store suspect info
        self.suspect = (pkt["srcip"], pkt["srcmac"], pkt["inport"], pkt["switch"])
        self.suspect_guilt = True
        self.query.register_callback(self.log_request_doublecheck)

        # assemble ARP request params
        switch = pkt["switch"]
        outport = pkt["inport"]
        srcip   = pkt['dstip']
        srcmac  = self.cd.get_mac_of(srcip)
        dstmac  = "ff:ff:ff:ff:ff:ff"
        dstip   = pkt["srcip"]
        # send request
        send_arp(REQUEST,self.network,switch,outport,srcip,srcmac,dstip,dstmac)

        # issue thread to check
        self.check_thread2 = threading.Thread(target=self.check_request_doublecheck)
        self.check_thread2.daemon = True
        self.check_thread2.start()
        return