Example #1
0
 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, pxe):
         return
         
     start_time = time.time()
     mac = None
     try:
         mac = packet.getHardwareAddress()
     except:
         pass
     if not mac: #IP/client-ID-based lookup; not supported.
         self._logDiscardedPacket()
         return
         
     if not [None for (ignored_mac, timeout) in self._ignored_addresses if mac == ignored_mac]:
         if not self._logDHCPAccess(mac):
             self._logDiscardedPacket()
             return
             
         src.logging.writeLog('DHCPLEASEQUERY for %(mac)s' % {
          'mac': mac,
         })
         
         try:
             result = self._sql_broker.lookupMAC(mac) or conf.handleUnknownMAC(mac)
             if result:
                 packet.transformToDHCPLeaseActivePacket()
                 if packet.setOption('yiaddr', ipToList(result[0])):
                     self._sendDHCPPacket(packet, source_address, 'LEASEACTIVE', mac, result[0], pxe)
                 else:
                     _logInvalidValue('ip', result[0], result[-2], result[-1])
             else:
                 packet.transformToDHCPLeaseUnknownPacket()
                 self._sendDHCPPacket(packet, source_address, 'LEASEUNKNOWN', mac, '?.?.?.?', pxe)
         except Exception, e:
             src.logging.sendErrorReport('Unable to respond for %(mac)s' % {'mac': mac,}, e)
Example #2
0
 def _handleDHCPDecline(self, packet, source_address, pxe):
     """
     Informs the operator of a potential IP collision on the network.
     
     This function checks to make sure the MAC isn't ignored or acting
     maliciously, then checks 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 a benign message is logged and the operator is informed; if not,
     the decline is flagged as a malicious act.
     
     @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.
     """
     if not self._evaluateRelay(packet, pxe):
         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
             
         if '.'.join(map(str, packet.getOption("server_identifier"))) == self._server_address: #Rejected!
             ip = '.'.join(map(str, packet.getOption("requested_ip_address")))
             result = self._sql_broker.lookupMAC(mac) or conf.handleUnknownMAC(mac)
             if result and result[0] == ip: #Known client.
                 src.logging.writeLog('DHCPDECLINE from %(mac)s for %(ip)s on (%(subnet)s, %(serial)i)' % {
                  'ip': ip,
                  'mac': mac,
                  'subnet': result[9],
                  'serial': result[10],
                 })
                 src.logging.sendDeclineReport(mac, ip, result[9], result[10])
             else:
                 src.logging.writeLog('Misconfigured client %(mac)s sent DHCPDECLINE for %(ip)s' % {
                  'ip': ip,
                  'mac': mac,
                 })
         else:
             self._logDiscardedPacket()
     else:
         self._logDiscardedPacket()
     self._logTimeTaken(time.time() - start_time)
Example #3
0
 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, pxe):
         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)
             
         src.logging.writeLog('DHCPINFORM from %(mac)s' % {
          'mac': mac,
         })
         
         if not ciaddr:
             src.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) or conf.handleUnknownMAC(mac)
             if result:
                 packet.transformToDHCPAckPacket()
                 pxe_options = packet.extractPXEOptions()
                 vendor_options = packet.extractVendorOptions()
                 self._loadDHCPPacket(packet, result, True)
                 if conf.loadDHCPPacket(
                  packet,
                  mac, tuple(ipToList(result[0])), giaddr,
                  result[9], result[10],
                  pxe and pxe_options, vendor_options
                 ):
                     self._sendDHCPPacket(packet, source_address, 'ACK', mac, s_ciaddr, pxe)
                 else:
                     src.logging.writeLog('Ignoring %(mac)s per loadDHCPPacket()' % {
                      'mac': mac,
                     })
                     self._logDiscardedPacket()
             else:
                 src.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:
             src.logging.sendErrorReport('Unable to respond to %(mac)s' % {'mac': mac,}, e)
Example #4
0
 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, pxe):
         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)
             
         if sid and not ciaddr: #SELECTING
             if s_sid == self._server_address: #Chosen!
                 src.logging.writeLog('DHCPREQUEST:SELECTING from %(mac)s' % {
                  'mac': mac,
                 })
                 try:
                     result = self._sql_broker.lookupMAC(mac) or conf.handleUnknownMAC(mac)
                     if result and (not ip or result[0] == s_ip):
                         packet.transformToDHCPAckPacket()
                         pxe_options = packet.extractPXEOptions()
                         vendor_options = packet.extractVendorOptions()
                         self._loadDHCPPacket(packet, result)
                         if conf.loadDHCPPacket(
                          packet,
                          mac, tuple(ipToList(result[0])), giaddr,
                          result[9], result[10],
                          pxe and pxe_options, vendor_options
                         ):
                             self._sendDHCPPacket(packet, source_address, 'ACK', mac, s_ip, pxe)
                         else:
                             src.logging.writeLog('Ignoring %(mac)s per loadDHCPPacket()' % {
                              'mac': mac,
                             })
                             self._logDiscardedPacket()
                     else:
                         packet.transformToDHCPNackPacket()
                         self._sendDHCPPacket(packet, source_address, 'NAK', mac, 'NO-MATCH', pxe)
                 except Exception, e:
                     src.logging.sendErrorReport('Unable to respond to %(mac)s' % {'mac': mac,}, e)
             else:
                 self._logDiscardedPacket()
         elif not sid and not ciaddr and ip: #INIT-REBOOT
             src.logging.writeLog('DHCPREQUEST:INIT-REBOOT from %(mac)s' % {
              'mac': mac,
             })
             try:
                 result = self._sql_broker.lookupMAC(mac) or conf.handleUnknownMAC(mac)
                 if result and result[0] == s_ip:
                     packet.transformToDHCPAckPacket()
                     pxe_options = packet.extractPXEOptions()
                     vendor_options = packet.extractVendorOptions()
                     self._loadDHCPPacket(packet, result)
                     if conf.loadDHCPPacket(
                      packet,
                      mac, tuple(ip), giaddr,
                      result[9], result[10],
                      pxe and pxe_options, vendor_options
                     ):
                         self._sendDHCPPacket(packet, source_address, 'ACK', mac, s_ip, pxe)
                     else:
                         src.logging.writeLog('Ignoring %(mac)s per loadDHCPPacket()' % {
                          'mac': mac,
                         })
                         self._logDiscardedPacket()
                 else:
                     packet.transformToDHCPNackPacket()
                     self._sendDHCPPacket(packet, source_address, 'NAK', mac, s_ip, pxe)
             except Exception, e:
                 src.logging.sendErrorReport('Unable to respond to %(mac)s' % {'mac': mac,}, e)
Example #5
0
 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.
     """
     if not self._evaluateRelay(packet, pxe):
         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
             
         src.logging.writeLog('DHCPDISCOVER from %(mac)s' % {
          'mac': mac,
         })
         
         try:
             result = self._sql_broker.lookupMAC(mac) or conf.handleUnknownMAC(mac)
             if result:
                 rapid_commit = not packet.getOption('rapid_commit') is None
                 if rapid_commit:
                     packet.transformToDHCPAckPacket()
                     packet.forceOption('rapid_commit', [])
                 else:
                     packet.transformToDHCPOfferPacket()
                 pxe_options = packet.extractPXEOptions()
                 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 and pxe_options, vendor_options
                 ):
                     if rapid_commit:
                         self._sendDHCPPacket(packet, source_address, 'ACK-rapid', mac, result[0], pxe)
                     else:
                         self._sendDHCPPacket(packet, source_address, 'OFFER', mac, result[0], pxe)
                 else:
                     src.logging.writeLog('Ignoring %(mac)s per loadDHCPPacket()' % {
                      'mac': mac,
                     })
                     self._logDiscardedPacket()
             else:
                 if conf.AUTHORITATIVE:
                     packet.transformToDHCPNackPacket()
                     self._sendDHCPPacket(packet, source_address, 'NAK', mac, '?.?.?.?', pxe)
                 else:
                     src.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:
             src.logging.sendErrorReport('Unable to respond to %(mac)s' % {'mac': mac,}, e)
Example #6
0
 if conf.NAK_RENEWALS and not pxe:
     packet.transformToDHCPNackPacket()
     self._sendDHCPPacket(packet, source_address, 'NAK', mac, 'NAK_RENEWALS', pxe)
 else:
     renew = source_address[0] not in ('255.255.255.255', '0.0.0.0', '')
     if renew:
         src.logging.writeLog('DHCPREQUEST:RENEW from %(mac)s' % {
          'mac': mac,
         })
     else:
         src.logging.writeLog('DHCPREQUEST:REBIND from %(mac)s' % {
          'mac': mac,
         })
         
     try:
         result = self._sql_broker.lookupMAC(mac) or conf.handleUnknownMAC(mac)
         if result and result[0] == s_ciaddr:
             packet.transformToDHCPAckPacket()
             pxe_options = packet.extractPXEOptions()
             vendor_options = packet.extractVendorOptions()
             packet.setOption('yiaddr', ciaddr)
             self._loadDHCPPacket(packet, result)
             if conf.loadDHCPPacket(
              packet,
              mac, tuple(ciaddr), giaddr,
              result[9], result[10],
              pxe and pxe_options, vendor_options
             ):
                 self._sendDHCPPacket(packet, (s_ciaddr, 0), 'ACK', mac, s_ciaddr, pxe)
             else:
                 src.logging.writeLog('Ignoring %(mac)s per loadDHCPPacket()' % {