Esempio n. 1
0
 def test__returns_server_identifier_if_included(self):
     server_ip = factory.make_ip_address(ipv6=False)
     packet = factory.make_dhcp_packet(
         include_server_identifier=True, server_ip=server_ip)
     dhcp = DHCP(packet)
     self.assertThat(dhcp.is_valid(), Equals(True))
     self.assertThat(dhcp.server_identifier, Equals(IPAddress(server_ip)))
Esempio n. 2
0
 def test_is_valid_returns_false_for_truncated_option_value(self):
     packet = factory.make_dhcp_packet(truncated_option_value=True)
     dhcp = DHCP(packet)
     self.assertThat(dhcp.is_valid(), Equals(False))
     self.assertThat(
         dhcp.invalid_reason, DocTestMatches("Truncated DHCP option value.")
     )
Esempio n. 3
0
 def test_is_valid_returns_false_for_invalid_cookie(self):
     packet = factory.make_dhcp_packet(bad_cookie=True)
     dhcp = DHCP(packet)
     self.assertThat(dhcp.is_valid(), Equals(False))
     self.assertThat(
         dhcp.invalid_reason, DocTestMatches("Invalid DHCP cookie.")
     )
Esempio n. 4
0
    def send_requests_and_await_replies(self):
        """Sends out DHCP requests and waits for their replies.

        This method is intended to run under `deferToThread()`.

        Calls the reactor using `blockingCallFromThread` to queue the request
        packets.

        Blocks for ~10 seconds while checking for DHCP offers.

        :returns: `set` of `DHCPServer` objects.
        """
        # Since deferToThread() might be delayed until the next thread is
        # available, it's better to kick off the DHCP requests from the
        # spawned thread rather than hoping the thread starts running after
        # we kick off the requests.
        blockingCallFromThread(self.clock, self.deferDHCPRequests)
        servers = set()
        # Convert the transaction_id to an integer so we can test it against
        # what the parsed DHCP packet will return.
        xid = int.from_bytes(self.transaction_id, byteorder="big")
        with udp_socket() as sock:
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
            # Note: the empty string is the equivalent of INADDR_ANY.
            sock.bind(("", BOOTP_CLIENT_PORT))
            # The timeout has to be relatively small, since we wake up every
            # timeout interval to check the elapsed time.
            sock.settimeout(0.5)
            runtime = 0
            # Use a monotonic clock to ensure leaping backward in time won't
            # cause an infinite loop.
            start_time = time.monotonic()
            while runtime < REPLY_TIMEOUT:
                try:
                    # Use recvfrom() to check the source IP for the request.
                    # It could be interesting in cases where DHCP relay is in
                    # use.
                    data, (address, port) = sock.recvfrom(2048)
                except socket.timeout:
                    continue
                else:
                    offer = DHCP(data)
                    if not offer.is_valid():
                        log.info(
                            "Invalid DHCP response received from {address} "
                            "on '{ifname}': {reason}",
                            address=address,
                            ifname=self.ifname,
                            reason=offer.invalid_reason,
                        )
                    elif offer.packet.xid == xid:
                        # Offer matches our transaction ID, so check if it has
                        # a Server Identifier option.
                        server = offer.server_identifier
                        if server is not None:
                            servers.add(DHCPServer(server, address))
                finally:
                    runtime = time.monotonic() - start_time
        return servers
Esempio n. 5
0
 def test__is_valid_returns_false_for_truncated_option_length(self):
     packet = factory.make_dhcp_packet(truncated_option_length=True)
     dhcp = DHCP(packet)
     self.assertThat(dhcp.is_valid(), Equals(False))
     self.assertThat(
         dhcp.invalid_reason,
         DocTestMatches("Truncated length field in DHCP option."),
     )
Esempio n. 6
0
 def test__server_identifier_none_if_not_included(self):
     packet = factory.make_dhcp_packet(
         include_server_identifier=False)
     dhcp = DHCP(packet)
     self.assertThat(dhcp.is_valid(), Equals(True))
     self.assertThat(dhcp.server_identifier, Is(None))
Esempio n. 7
0
 def test__is_valid_return_true_for_valid_packet(self):
     packet = factory.make_dhcp_packet()
     dhcp = DHCP(packet)
     self.assertThat(dhcp.is_valid(), Equals(True))