def _handleDHCPLeaseQuery(self, packet, source_address, pxe): """ Evaluates a DHCPLEASEQUERY request from a relay and determines whether a DHCPLEASEACTIVE or DHCPLEASEUNKNOWN should be sent. The logic here is to make sure the MAC isn't ignored or acting maliciously, then check the database to see whether it has an assigned IP. If it does, DHCPLEASEACTIVE is sent. Otherwise, DHCPLEASEUNKNOWN is sent. @type packet: L{libpydhcpserver.dhcp_packet.DHCPPacket} @param packet: The DHCPREQUEST to be evaluated. @type source_address: tuple @param source_address: The address (host, port) from which the request was received. @type pxe: bool @param pxe: True if the packet was received on the PXE port. """ if not self._evaluateRelay(packet): return start_time = time.time() mac = None #noinspection PyBroadException try: mac = packet.getHardwareAddress() except: pass if not mac: #IP/client-ID-based lookup; not supported. self._logDiscardedPacket() return vlan = packet.getVlanNum() if not [None for (ignored_mac, timeout) in self._ignored_addresses if mac == ignored_mac]: if not self._logDHCPAccess(mac): self._logDiscardedPacket() return logging.writeLog('DHCPLEASEQUERY for %(mac)s on vlan %(vlan)s' % { 'mac': mac, 'vlan': vlan }) try: result = self._sql_broker.lookupMAC(mac) if result: packet.transformToDHCPLeaseActivePacket() if packet.setOption('yiaddr', ipToList(result[0])): self._sendDHCPPacket(packet, source_address, 'LEASEACTIVE', mac, result[0]) else: _logInvalidValue('ip', result[0], result[-2], result[-1]) else: packet.transformToDHCPLeaseUnknownPacket() self._sendDHCPPacket(packet, source_address, 'LEASEUNKNOWN', mac, '?.?.?.?') except Exception, e: logging.sendErrorReport('Unable to respond for %(mac)s' % {'mac': mac,}, e)
def run(self): """ Runs the DHCP server indefinitely. In the event of an unexpected error, e-mail will be sent and processing will continue with the next request. """ logging.writeLog('Running DHCP server') while True: try: self._dhcp_server.getNextDHCPPacket() except select.error: logging.writeLog('Suppressed non-fatal select() error in DHCP module') except Exception, e: logging.sendErrorReport('Unhandled exception', e)
def _handleDHCPInform(self, packet, source_address, pxe): """ Evaluates a DHCPINFORM request from a client and determines whether a DHCPACK should be sent. The logic here is to make sure the MAC isn't ignored or acting maliciously, then check the database to see whether it has an assigned IP. If it does, and the IP it thinks it has a right to matches this IP, then an ACK is sent, along with all relevant options; if not, the request is ignored. @type packet: L{libpydhcpserver.dhcp_packet.DHCPPacket} @param packet: The DHCPREQUEST to be evaluated. @type source_address: tuple @param source_address: The address (host, port) from which the request was received. @type pxe: bool @param pxe: True if the packet was received on the PXE port. """ if not self._evaluateRelay(packet): return start_time = time.time() mac = packet.getHardwareAddress() if not [None for (ignored_mac, timeout) in self._ignored_addresses if mac == ignored_mac]: if not self._logDHCPAccess(mac): self._logDiscardedPacket() return ciaddr = packet.getOption("ciaddr") giaddr = packet.getOption("giaddr") s_ciaddr = '.'.join(map(str, ciaddr)) if not ciaddr or ciaddr == [0,0,0,0]: ciaddr = None if not giaddr or giaddr == [0,0,0,0]: giaddr = None else: giaddr = tuple(giaddr) vlan = packet.getVlanNum() logging.writeLog('DHCPINFORM from %(mac)s on vlan %(vlan)s' % { 'mac': mac, 'vlan': vlan }) if not ciaddr: logging.writeLog('%(mac)s sent malformed packet; ignoring for %(time)i seconds' % { 'mac': mac, 'time': conf.UNAUTHORIZED_CLIENT_TIMEOUT, }) self._stats_lock.acquire() self._ignored_addresses.append([mac, conf.UNAUTHORIZED_CLIENT_TIMEOUT]) self._stats_lock.release() self._logDiscardedPacket() return try: result = self._sql_broker.lookupMAC(mac) if result: packet.transformToDHCPAckPacket() vendor_options = packet.extractVendorOptions() self._loadDHCPPacket(packet, result, True) if conf.loadDHCPPacket( packet, mac, tuple(ipToList(result[0])), giaddr, result[9], result[10], pxe, vendor_options ): self._sendDHCPPacket(packet, source_address, 'ACK', mac, s_ciaddr) else: logging.writeLog('Ignoring %(mac)s per loadDHCPPacket()' % { 'mac': mac, }) self._logDiscardedPacket() else: logging.writeLog('%(mac)s unknown; ignoring for %(time)i seconds' % { 'mac': mac, 'time': conf.UNAUTHORIZED_CLIENT_TIMEOUT, }) self._stats_lock.acquire() self._ignored_addresses.append([mac, conf.UNAUTHORIZED_CLIENT_TIMEOUT]) self._stats_lock.release() self._logDiscardedPacket() except Exception, e: logging.sendErrorReport('Unable to respond to %(mac)s' % {'mac': mac,}, e)
def _handleDHCPRequest(self, packet, source_address, pxe): """ Evaluates a DHCPREQUEST request from a client and determines whether a DHCPACK should be sent. The logic here is to make sure the MAC isn't ignored or acting maliciously, then check the database to see whether it has an assigned IP. If it does, and the IP it thinks it has a right to matches this IP, then an ACK is sent, along with all relevant options; if not, a DHCPNAK is sent to inform the client that it is not allowed to use the requested IP, forcing it to DISCOVER a new one. If policy forbids RENEW and REBIND operations, perhaps to prepare for a new configuration rollout, all such requests are NAKed immediately. @type packet: L{libpydhcpserver.dhcp_packet.DHCPPacket} @param packet: The DHCPREQUEST to be evaluated. @type source_address: tuple @param source_address: The address (host, port) from which the request was received. @type pxe: bool @param pxe: True if the packet was received on the PXE port. """ if not self._evaluateRelay(packet): return start_time = time.time() mac = packet.getHardwareAddress() if not [None for (ignored_mac, timeout) in self._ignored_addresses if mac == ignored_mac]: if not self._logDHCPAccess(mac): self._logDiscardedPacket() return ip = packet.getOption("requested_ip_address") sid = packet.getOption("server_identifier") ciaddr = packet.getOption("ciaddr") giaddr = packet.getOption("giaddr") s_ip = ip and '.'.join(map(str, ip)) s_sid = sid and '.'.join(map(str, sid)) s_ciaddr = ciaddr and '.'.join(map(str, ciaddr)) if not ip or ip == [0,0,0,0]: ip = None if not sid or sid == [0,0,0,0]: sid = None if not ciaddr or ciaddr == [0,0,0,0]: ciaddr = None if not giaddr or giaddr == [0,0,0,0]: giaddr = None else: giaddr = tuple(giaddr) vlan = packet.getVlanNum() if sid and not ciaddr: #SELECTING if s_sid == self._server_address: #Chosen! logging.writeLog('DHCPREQUEST:SELECTING from %(mac)s on vlan %(vlan)s' % { 'mac': mac, 'vlan': vlan }) try: result = self._sql_broker.lookupMAC(mac) if result and (not ip or result[0] == s_ip): packet.transformToDHCPAckPacket() vendor_options = packet.extractVendorOptions() self._loadDHCPPacket(packet, result) if conf.loadDHCPPacket( packet, mac, tuple(ipToList(result[0])), giaddr, result[9], result[10], pxe, vendor_options ): self._sendDHCPPacket(packet, source_address, 'ACK', mac, s_ip) else: logging.writeLog('Ignoring %(mac)s per loadDHCPPacket()' % { 'mac': mac, }) self._logDiscardedPacket() else: packet.transformToDHCPNackPacket() self._sendDHCPPacket(packet, source_address, 'NAK', mac, 'NO-MATCH') except Exception, e: logging.sendErrorReport('Unable to respond to %(mac)s' % {'mac': mac,}, e) else: self._logDiscardedPacket() elif not sid and not ciaddr and ip: #INIT-REBOOT logging.writeLog('DHCPREQUEST:INIT-REBOOT from %(mac)s on vlan %(vlan)s' % { 'mac': mac, 'vlan': vlan }) try: result = self._sql_broker.lookupMAC(mac) if result and result[0] == s_ip: packet.transformToDHCPAckPacket() vendor_options = packet.extractVendorOptions() self._loadDHCPPacket(packet, result) if conf.loadDHCPPacket( packet, mac, tuple(ip), giaddr, result[9], result[10], pxe, vendor_options ): self._sendDHCPPacket(packet, source_address, 'ACK', mac, s_ip) else: logging.writeLog('Ignoring %(mac)s per loadDHCPPacket()' % { 'mac': mac, }) self._logDiscardedPacket() else: packet.transformToDHCPNackPacket() self._sendDHCPPacket(packet, source_address, 'NAK', mac, s_ip) except Exception, e: logging.sendErrorReport('Unable to respond to %(mac)s' % {'mac': mac,}, e)
def _handleDHCPDiscover(self, packet, source_address, pxe): """ Evaluates a DHCPDISCOVER request from a client and determines whether a DHCPOFFER should be sent. The logic here is to make sure the MAC isn't ignored or acting maliciously, then check the database to see whether it has an assigned IP. If it does, that IP is offered, along with all relevant options; if not, the MAC is ignored to mitigate spam from follow-up DHCPDISCOVERS. @type packet: L{libpydhcpserver.dhcp_packet.DHCPPacket} @param packet: The DHCPDISCOVER to be evaluated. @type source_address: tuple @param source_address: The address (host, port) from which the request was received. @type pxe: bool @param pxe: True if the packet was received on the PXE port. """ #assert False from conf import PKT_CAPT PKT_CAPT.append((packet, source_address, pxe)) if not self._evaluateRelay(packet): return start_time = time.time() mac = packet.getHardwareAddress() vlan = packet.getVlanNum() if not [None for (ignored_mac, timeout) in self._ignored_addresses if mac == ignored_mac]: if not self._logDHCPAccess(mac): self._logDiscardedPacket() return logging.writeLog('DHCPDISCOVER from %(mac)s on vlan %(vlan)s' % { 'mac': mac, 'vlan': vlan }) try: result = self._sql_broker.lookupMAC(mac) if result: rapid_commit = not packet.getOption('rapid_commit') is None if rapid_commit: packet.transformToDHCPAckPacket() packet.forceOption('rapid_commit', []) else: packet.transformToDHCPOfferPacket() vendor_options = packet.extractVendorOptions() self._loadDHCPPacket(packet, result) giaddr = packet.getOption("giaddr") if not giaddr or giaddr == [0,0,0,0]: giaddr = None else: giaddr = tuple(giaddr) if conf.loadDHCPPacket( packet, mac, tuple(ipToList(result[0])), giaddr, result[9], result[10], pxe, vendor_options ): if rapid_commit: self._sendDHCPPacket(packet, source_address, 'ACK-rapid', mac, result[0]) else: self._sendDHCPPacket(packet, source_address, 'OFFER', mac, result[0]) else: logging.writeLog('Ignoring %(mac)s per loadDHCPPacket()' % { 'mac': mac, }) self._logDiscardedPacket() else: if conf.AUTHORITATIVE: packet.transformToDHCPNackPacket() self._sendDHCPPacket(packet, source_address, 'NAK', mac, '?.?.?.?') else: logging.writeLog('%(mac)s unknown; ignoring for %(time)i seconds' % { 'mac': mac, 'time': conf.UNAUTHORIZED_CLIENT_TIMEOUT, }) self._stats_lock.acquire() self._ignored_addresses.append([mac, conf.UNAUTHORIZED_CLIENT_TIMEOUT]) self._stats_lock.release() except Exception, e: logging.sendErrorReport('Unable to respond to %(mac)s' % {'mac': mac,}, e)
pxe, vendor_options ): self._sendDHCPPacket(packet, (s_ciaddr, 0), 'ACK', mac, s_ciaddr) else: logging.writeLog('Ignoring %(mac)s per loadDHCPPacket()' % { 'mac': mac, }) self._logDiscardedPacket() else: if renew: packet.transformToDHCPNackPacket() self._sendDHCPPacket(packet, (s_ciaddr, 0), 'NAK', mac, s_ciaddr) else: self._logDiscardedPacket() except Exception, e: logging.sendErrorReport('Unable to respond to %(mac)s' % {'mac': mac,}, e) else: logging.writeLog('DHCPREQUEST:UNKNOWN (%(sid)s %(ciaddr)s %(ip)s) from %(mac)s on vlan %(vlan)s' % { 'sid': str(sid), 'ciaddr': str(ciaddr), 'ip': str(ip), 'mac': mac, 'vlan': vlan, }) self._logDiscardedPacket() else: self._logDiscardedPacket() self._logTimeTaken(time.time() - start_time) def _handleDHCPInform(self, packet, source_address, pxe): """