This file is indexed.

/usr/lib/python3/dist-packages/provisioningserver/pserv_services/dhcp_probe_service.py is in python3-maas-provisioningserver 2.0.0~beta3+bzr4941-0ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# Copyright 2014-2016 Canonical Ltd.  This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).

""" DHCP probing service."""

__all__ = [
    "DHCPProbeService",
    ]


from datetime import timedelta
import socket

from provisioningserver.dhcp.detect import probe_interface
from provisioningserver.logger.log import get_maas_logger
from provisioningserver.rpc.exceptions import NoConnectionsAvailable
from provisioningserver.rpc.region import ReportForeignDHCPServer
from provisioningserver.utils.network import get_all_interfaces_definition
from provisioningserver.utils.twisted import (
    pause,
    retries,
)
from twisted.application.internet import TimerService
from twisted.internet.defer import inlineCallbacks
from twisted.internet.threads import deferToThread
from twisted.protocols.amp import UnhandledCommand


maaslog = get_maas_logger("dhcp.probe")


class DHCPProbeService(TimerService, object):
    """Service to probe for DHCP servers on the rack controller interface's.

    Built on top of Twisted's `TimerService`.

    :param reactor: An `IReactor` instance.
    """

    check_interval = timedelta(minutes=10).total_seconds()

    def __init__(self, client_service, reactor):
        # Call self.try_probe_dhcp() every self.check_interval.
        super(DHCPProbeService, self).__init__(
            self.check_interval, self.try_probe_dhcp)
        self.clock = reactor
        self.client_service = client_service

    def _get_interfaces(self):
        """Return the interfaces for this rack controller."""
        d = deferToThread(get_all_interfaces_definition)
        d.addCallback(lambda interfaces: [
            name
            for name, info in interfaces.items()
            if info["enabled"]
        ])
        return d

    def _inform_region_of_dhcp(self, client, name, dhcp_ip):
        """Tell the region about the DHCP server.

        :param client: The RPC client to use.
        :param name: The name of the network interface where the rogue
            DHCP server was found.
        :param dhcp_ip: The IP address of the DHCP server.
        """

        def eb_unhandled(failure):
            failure.trap(UnhandledCommand)
            # Not a lot we can do here... The region doesn't support
            # this method yet.
            maaslog.error(
                "Unable to inform region of DHCP server: the region "
                "does not yet support the ReportForeignDHCPServer RPC "
                "method.")

        d = client(
            ReportForeignDHCPServer, system_id=client.localIdent,
            interface_name=name, dhcp_ip=dhcp_ip)
        d.addErrback(eb_unhandled)
        return d

    @inlineCallbacks
    def probe_dhcp(self):
        """Find all the interfaces on this rack controller and probe for
        DHCP servers.
        """
        client = None
        for elapsed, remaining, wait in retries(15, 5, self.clock):
            try:
                client = self.client_service.getClient()
                break
            except NoConnectionsAvailable:
                yield pause(wait, self.clock)
        else:
            maaslog.error(
                "Can't initiate DHCP probe, no RPC connection to region.")
            return

        # Iterate over interfaces and probe each one.
        interfaces = yield self._get_interfaces()
        for interface in interfaces:
            try:
                servers = yield deferToThread(probe_interface, interface)
            except socket.error:
                maaslog.error(
                    "Failed to probe sockets; did you configure authbind as "
                    "per HACKING.txt?")
                break
            else:
                if len(servers) > 0:
                    # Only send one, if it gets cleared out then the
                    # next detection pass will send a different one, if it
                    # still exists.
                    yield self._inform_region_of_dhcp(
                        client, interface, servers.pop())
                else:
                    yield self._inform_region_of_dhcp(
                        client, interface, None)

    @inlineCallbacks
    def try_probe_dhcp(self):
        maaslog.debug("Running periodic DHCP probe.")
        try:
            yield self.probe_dhcp()
        except Exception as error:
            maaslog.error(
                "Unable to probe for DHCP servers: %s",
                str(error))
        else:
            maaslog.debug("Finished periodic DHCP probe.")