def do_beaconing(args, interfaces=None): """Sends out beacons based on the given arguments, and waits for replies. :param args: The command-line arguments. :param interfaces: The interfaces to send out beacons on. Must be the result of `get_all_interfaces_definition()`. """ if args.source is None: source_ip = '::' else: source_ip = args.source protocol = BeaconingSocketProtocol(reactor, process_incoming=True, debug=True, interface=source_ip, port=args.port, interfaces=interfaces) if args.destination is None: destination_ip = "::ffff:" + BEACON_IPV4_MULTICAST elif ':' not in args.destination: destination_ip = "::ffff:" + args.destination else: destination_ip = args.destination if "224.0.0.118" in destination_ip: protocol.send_multicast_beacons(interfaces, verbose=args.verbose) else: log.msg("Sending unicast beacon to '%s'..." % destination_ip) beacon = create_beacon_payload("solicitation") protocol.send_beacon(beacon, (destination_ip, BEACON_PORT)) reactor.callLater(args.timeout, lambda: reactor.stop()) reactor.run() return protocol
def test__sends_and_receives_unicast_beacons(self): # Note: Always use a random port for testing. (port=0) logger = self.useFixture(TwistedLoggerFixture()) protocol = BeaconingSocketProtocol( reactor, port=0, process_incoming=True, loopback=True, interface="::", debug=True, ) self.assertThat(protocol.listen_port, Not(Is(None))) listen_port = protocol.listen_port._realPortNumber self.write_secret() beacon = create_beacon_payload("solicitation", {}) rx_uuid = beacon.payload["uuid"] destination = random.choice(["::ffff:127.0.0.1", "::1"]) protocol.send_beacon(beacon, (destination, listen_port)) # Pretend we didn't send this packet. Otherwise we won't reply to it. # We have to do this now, before the reactor runs again. transmitted = protocol.tx_queue.pop(rx_uuid, None) # Since we've instructed the protocol to loop back packets for testing, # it should have sent a multicast solicitation, received it back, sent # an advertisement, then received it back. So we'll wait for two # packets to be sent. yield wait_for_rx_packets(protocol, 2) # Grab the beacon we know we transmitted and then received. received = protocol.rx_queue.pop(rx_uuid, None) self.assertThat(transmitted, Equals(beacon)) self.assertThat(received[0].json["payload"]["uuid"], Equals(rx_uuid)) # Grab the subsequent packets from the queues. transmitted = protocol.tx_queue.popitem()[1] received = protocol.rx_queue.popitem()[1] # We should have received a second packet to ack the first beacon. self.assertThat(received[0].json["payload"]["acks"], Equals(rx_uuid)) # We should have transmitted an advertisement in response to the # solicitation. self.assertThat(transmitted.type, Equals("advertisement")) # This tests that the post gets closed properly; otherwise the test # suite will complain about things left in the reactor. yield protocol.stopProtocol() # In debug mode, the logger should have printed each packet. self.assertThat( logger.output, DocTestMatches("...Beacon received:...Own beacon received:..."), )