Exemple #1
0
def getMaskAndSpace(address, prefixlen):
    addresses = 2**(32 - prefixlen)
    mask = util.iptoint(address)
    mask = bin(mask)
    mask = mask[:-(32 - prefixlen)]
    mask = mask + ('0' * (32 - prefixlen))
    mask = int(mask[2:], 2)
    return (util.inttoip(mask), addresses)
Exemple #2
0
                 'ignoring %s request' % (item, mac_str))
             return
         if not self.acl[item]:
             self.log.info('%s access is disabled, '
                 'ignoring %s request' % (item, mac_str))
             return
     else:
         item = locals()['%s_str' % self.access]
     self.log.info('%s access is authorized, '
                   'request will be satisfied' % item)
 # construct reply
 buf[BOOTP_OP] = BOOTREPLY
 self.log.info('Client IP: %s' % socket.inet_ntoa(buf[7]))
 if buf[BOOTP_CIADDR] == '\x00\x00\x00\x00':
     self.log.debug('Client needs its address')
     ipaddr = iptoint(self.pool_start)
     ip = None
     if mac_str in self.ippool:
         ip = self.ippool[mac_str]
         self.log.info('Lease for MAC %s already defined as IP %s' % \
                         (mac_str, ip))
     else:
         for idx in xrange(self.pool_count):
             ipkey = inttoip(ipaddr+idx)
             self.log.debug('Check for IP %s' % ipkey)
             if ipkey not in self.ippool.values():
                 self.ippool[mac_str] = ipkey
                 ip = ipkey
                 break
     if not ip:
         raise BootpError('No more IP available in definined pool')
Exemple #3
0
                           'ignoring %s request' % (item, mac_str))
             return
         if not self.acl[item]:
             self.log.info('%s access is disabled, '
                           'ignoring %s request' % (item, mac_str))
             return
     else:
         item = locals()['%s_str' % self.access]
     self.log.info('%s access is authorized, '
                   'request will be satisfied' % item)
 # construct reply
 buf[BOOTP_OP] = BOOTREPLY
 self.log.info('Client IP: %s' % socket.inet_ntoa(buf[7]))
 if buf[BOOTP_CIADDR] == '\x00\x00\x00\x00':
     self.log.debug('Client needs its address')
     ipaddr = iptoint(self.pool_start)
     ip = None
     if mac_str in self.ippool:
         ip = self.ippool[mac_str]
         self.log.info('Lease for MAC %s already defined as IP %s' % \
                         (mac_str, ip))
     else:
         for idx in xrange(self.pool_count):
             ipkey = inttoip(ipaddr + idx)
             self.log.debug('Check for IP %s' % ipkey)
             if ipkey not in self.ippool.values():
                 self.ippool[mac_str] = ipkey
                 ip = ipkey
                 break
     if not ip:
         raise BootpError('No more IP available in definined pool')
Exemple #4
0
def initAddresses(the_queue, subspaces):
    for space in subspaces:
        mask, addresses = getMaskAndSpace(
            space.split('/')[0], int(space.split('/')[1]))
        for i in range(0, addresses):
            the_queue.put(util.inttoip(util.iptoint(mask) + i))
Exemple #5
0
             return
         if not self.acl[item]:
             self.log.info('%s access is disabled, '
                 'ignoring %s request' % (item, mac_str))
             return
     else:
         item = locals()['%s_str' % self.access]
     self.log.info('%s access is authorized, '
                   'request will be satisfied' % item)
 # construct reply
 buf[BOOTP_HOPS] = 0
 buf[BOOTP_OP] = BOOTREPLY
 self.log.info('Client IP: %s' % socket.inet_ntoa(buf[7]))
 if buf[BOOTP_CIADDR] == '\x00\x00\x00\x00':
     self.log.debug('Client needs its address')
     ipaddr = iptoint(self.pool_start)
     ip = None
     if mac_str in self.ippool:
         ip = self.ippool[mac_str]
         self.log.info('Lease for MAC %s already defined as IP %s' % \
                         (mac_str, ip))
     else:
         ip = self.config.get(mac_str.lower(), "ipv4")
         if ip:
             self.ippool[mac_str] = ip
             self.log.info('Found reserved IP "%s" for MAC "%s"' %
                           (ip, mac_str))
         else:
             self.log.debug("No reserved IP found for MAC %s" % mac_str)
             for idx in xrange(self.pool_count):
                 ipkey = inttoip(ipaddr+idx)
Exemple #6
0
    def construct_reply(self, buf, host_params, state, req_addr, options, dhcp_msg_type, source_address):

        buf[BOOTP_OP] = BOOTREPLY
        self.log.info("Client IP: %s" % socket.inet_ntoa(buf[7]))
        self.log.info("BOOTP_CIADDR %r" % buf[BOOTP_CIADDR])

        if buf[BOOTP_CIADDR] == '\x00\x00\x00\x00':
            self.log.info("Client needs its address")

        self.log.info("Server netconfig is: {0}".format(self.server_config))

        mask = iptoint(self.server_config['mask'])
        reply_broadcast = iptoint(host_params['ip_address']) & mask
        reply_broadcast |= (~mask)&((1<<32)-1)
        buf[BOOTP_YIADDR] = socket.inet_aton(host_params['ip_address'])
        buf[BOOTP_SECS] = 0
        buf[BOOTP_FLAGS] = BOOTP_FLAGS_NONE

        req_addr = (req_addr[0], req_addr[1])

        self.log.info("Reply to: %s:%s" % req_addr)
        self.log.info("Options: {0}".format(options))

        buf[BOOTP_SIADDR] = socket.inet_aton(source_address)
        self.log.info("req_addr is: {0}".format(req_addr[0]))
        buf[BOOTP_GIADDR] = socket.inet_aton(req_addr[0])

        # sname
        buf[BOOTP_SNAME] = '.'.join(['unknown', 'localdomain'])
        # file

        ipxe_flag = self.is_this_ipxe(options)
        self.log.info("Ipxe flag: {0}".format(ipxe_flag))

        if self.is_this_ipxe(options):
            pxe_filename = "http://local.domain.ru/PXE/iboot.ipxe/${mac}"
        else:
            pxe_filename = host_params['pxe_filename']

        buf[BOOTP_FILE] = pxe_filename

        if not dhcp_msg_type:
            self.log.info("No DHCP message type found, discarding request")
            return
        if dhcp_msg_type == DHCP_DISCOVER:
            self.log.info("DHCP DISCOVER")
            dhcp_reply = DHCP_OFFER
            self.log.info("Offering lease for MAC %s: IP %s" % (host_params['mac'], host_params['ip_address']))
        elif dhcp_msg_type == DHCP_REQUEST:
            self.log.info("DHCP REQUEST")
            dhcp_reply = DHCP_ACK
            self.log.info("New lease for MAC %s: IP %s" % (host_params['mac'], host_params['ip_address']))
        elif dhcp_msg_type == DHCP_RELEASE:
            self.log.info("DHCP RELEASE")
    #        if not notify:
            return False
        elif dhcp_msg_type == DHCP_INFORM:
            self.log.info("DHCP INFORM")
            return False
        else:
            self.log.info("Unmanaged DHCP message: %d" % dhcp_msg_type)
            return

        # Store the filename
        if host_params['pxe_filename']:
            self.log.info("Filename for IP %s is '%s'" % (host_params['ip_address'], host_params['pxe_filename']))
            self.filepool[host_params['ip_address']] = host_params['pxe_filename']
        else:
            self.log.info("No filename defined for IP %s" % host_params['ip_address'])

        pkt = struct.pack(DHCPFormat, *buf)
        pkt += struct.pack('!BBB', DHCP_MSG, 1, dhcp_reply)

#        server = socket.inet_aton(self.server_config['ip_address'])
        server = socket.inet_aton(source_address)
        pkt += struct.pack('!BB4s', DHCP_SERVER, 4, server)

        pkt += struct.pack('!BBI', DHCP_LEASE_TIME, 4, int(str(28800)))

        mask = socket.inet_aton(host_params['mask'])
        pkt += struct.pack('!BB4s', DHCP_IP_MASK, 4, mask)

        gateway=socket.inet_aton(host_params['gateway'])
        pkt += struct.pack('!BB4s', DHCP_IP_GATEWAY, 4, gateway)

        dns = socket.inet_aton(host_params['dns'])
        pkt += struct.pack('!BB4s', DHCP_IP_DNS, 4, dns)
#        pkt += struct.pack('!BB%rs' % len(host_params['hostname']), DHCP_HOSTNAME, len(host_params['hostname']), host_params['hostname'])
        pkt += struct.pack('!BB%ds' % len(host_params['hostname']), DHCP_HOSTNAME, len(host_params['hostname']), host_params['hostname'])

        pkt += struct.pack('!BB%ds' % len(host_params['domain']), DHCP_DOMAIN, len(host_params['domain']), host_params['domain'])

        pkt += struct.pack('!BB%ds' % len(host_params['pxe_path']), DHCP_ROOT_PATH, len(host_params['pxe_path']), host_params['pxe_path'])

        reply_broadcast_ip = socket.inet_aton(inttoip(reply_broadcast))
        pkt += struct.pack('!BB4s', DHCP_BROADCAST_ADDR, 4, reply_broadcast_ip)

        vendor_spec_len = len(host_params['pxe_menu_http'])
        vendor_spec_len_all = len(host_params['pxe_menu_http']) + 2
        pkt += struct.pack('!BBBB%ds' % vendor_spec_len, DHCP_VENDOR_SPECIFIC, vendor_spec_len_all, DHCP_PXELINUX_PATHPREFIX,
                           vendor_spec_len, host_params['pxe_menu_http'])

        pkt += struct.pack('!BBI', DHCP_RENEWAL_TIME, 4, int(str(14400)))

        pkt += struct.pack('!BBI', DHCP_REBINDING_TIME, 4, int(str(25200)))

        pkt += struct.pack('!BB4s', DHCP_UNASSIGNED, 4, server)

        pkt += struct.pack('!BB', DHCP_END, 0)

        #if pxe:
        #    self.uuidpool[mac_addr] = uuid

        return pkt
Exemple #7
0
    def handle(self, sock, addr, data):
        sender = addr
        self.log.info('Sender: %s on socket %s' % (addr, sock.getsockname()))
        if len(data) < DHCPFormatSize:
            self.log.error('Cannot be a DHCP or BOOTP request - too small!')
        tail = data[DHCPFormatSize:]
        buf = list(struct.unpack(DHCPFormat, data[:DHCPFormatSize]))
        if buf[BOOTP_OP] != BOOTREQUEST:
            self.log.warn('Not a BOOTREQUEST')
            return
        options = self.parse_options(tail)
        if options is None:
            self.log.warn('Error in option parsing, ignore request')
            return

        # Extras (DHCP options)
        try:
            dhcp_msg_type = ord(options[53][0])
        except KeyError:
            dhcp_msg_type = None

        server_addr = self.netconfig['address']
        mac_addr = buf[BOOTP_CHADDR][:6]
        gi_addr = buf[BOOTP_GIADDR][:4]
        mac_str = ':'.join(['%02X' % ord(x) for x in mac_addr])
        gi_str = '.'.join(['%d' % ord(x) for x in gi_addr])
        self.log.debug("Gateway address: %s" % gi_str)
        # is the UUID received (PXE mode)
        if 97 in options and len(options[97]) == 17:
            uuid = options[97][1:]
            pxe = True
            self.log.info('PXE UUID has been received')
        # or retrieved from the cache (DHCP mode)
        else:
            uuid = self.uuidpool.get(mac_addr, None)
            pxe = False
            self.log.info('PXE UUID not present in request')
        uuid_str = uuid and ('%s-%s-%s-%s-%s' % \
            tuple([hexlify(x) for x in uuid[0:4], uuid[4:6], uuid[6:8],
                                       uuid[8:10], uuid[10:16]])).upper()
        if uuid_str:
            self.log.info('UUID is %s for MAC %s' % (uuid_str, mac_str))

        hostname = ''
        filename = ''

        # Basic state machine
        currentstate = self.states.setdefault(mac_str, self.ST_IDLE)
        newstate = currentstate
        if currentstate == self.ST_IDLE:
            if pxe and (dhcp_msg_type == DHCP_DISCOVER):
                # BIOS is booting up, and try to locate a DHCP server
                newstate = self.ST_PXE
        elif currentstate == self.ST_PXE:
            if not pxe and (dhcp_msg_type == DHCP_REQUEST):
                # OS is booting up, and confirm a previous DHCP dicovery
                newstate = self.ST_DHCP
        else: # currentstate == self.ST_DHCP
            if pxe:
                # OS was running but the BIOS is performing a DHCP request:
                # board has been restarted
                newstate = self.ST_PXE

        # if the state has not evolved from idle, there is nothing to do
        if newstate == self.ST_IDLE:
            self.log.info('Request from %s ignored (idle state)' % mac_str)
            sdhcp = self.config.get_bootp_allow_simple_dhcp()
            simple_dhcp = sdhcp and to_bool(sdhcp)
            if not simple_dhcp:
               return

        # construct reply
        buf[BOOTP_OP] = BOOTREPLY
        self.log.info('Client IP: %s' % socket.inet_ntoa(buf[7]))
        if buf[BOOTP_CIADDR] == '\x00\x00\x00\x00':
            self.log.debug('Client needs its address')
            host_data = self.get_host_data_for_mac(mac_str)
            ipaddr = host_data['address']

            self.log.debug("IPADDR: {0}".format(ipaddr))
            if not ipaddr:
                self.log.error("Can't get IP address!")
                return
            ip = None
            if mac_str in self.ippool:
                ip = self.ippool[mac_str]
                self.log.info('Lease for MAC %s already defined as IP %s' % \
                                (mac_str, ip))
            else:
                self.ippool[mac_str] = ipaddr
                ip = ipaddr

            if not ip:
                #raise BootpError('No more IP available in definined pool')
                self.log.error("Can not find IP assigned to mac: %s" % mac_str)
                return

            mask = iptoint(self.netconfig['mask'])
            reply_broadcast = iptoint(ip) & mask
            reply_broadcast |= (~mask)&((1<<32)-1)
            buf[BOOTP_YIADDR] = socket.inet_aton(ip)
            buf[BOOTP_SECS] = 0
            buf[BOOTP_FLAGS] = BOOTP_FLAGS_NONE
            addr = (inttoip(reply_broadcast), addr[1])
            self.log.debug('Reply to: %s:%s' % addr)
        else:
            buf[BOOTP_YIADDR] = buf[BOOTP_CIADDR]
            ip = socket.inet_ntoa(buf[BOOTP_YIADDR])
        buf[BOOTP_SIADDR] = socket.inet_aton(server_addr)
        if gi_addr:
            self.log.debug('Reply via gateway: %s' % gi_str)
            buf[BOOTP_GIADDR] = socket.inet_aton(gi_str)
        # sname
        buf[BOOTP_SNAME] = \
            '.'.join([host_data['hostname'], host_data['domain']])
        # file
        buf[BOOTP_FILE] = 'boot_file' in host_data and host_data['boot_file'] or self.config.get_bootp_default_boot_file()

        if not dhcp_msg_type:
            self.log.warn('No DHCP message type found, discarding request')
            return
        if dhcp_msg_type == DHCP_DISCOVER:
            self.log.debug('DHCP DISCOVER')
            dhcp_reply = DHCP_OFFER
            self.log.info('Offering lease for MAC %s: IP %s' % \
                          (mac_str, ip))
        elif dhcp_msg_type == DHCP_REQUEST:
            self.log.debug('DHCP REQUEST')
            dhcp_reply = DHCP_ACK
            self.log.info('New lease for MAC %s: IP %s' % \
                          (mac_str, ip))
        elif dhcp_msg_type == DHCP_RELEASE:
            self.log.info('DHCP RELEASE')
            if not self.notify:
                return
        elif dhcp_msg_type == DHCP_INFORM:
            self.log.info('DHCP INFORM')
            return
        elif dhcp_msg_type == DHCP_DECLINE:
            self.log.debug('DHCP DECLINE')
            return
        else:
            self.log.error('Unmanaged DHCP message: %d' % dhcp_msg_type)
            return

        pkt = struct.pack(DHCPFormat, *buf)
        pkt += struct.pack('!BBB', DHCP_MSG, 1, dhcp_reply)
        #server = socket.inet_aton(server_addr)
        # FIXME: Hardcoded relay and netmask
        # Add something in lines of:
        # networks:
        #     10.40.13.160:
        #         netmask: 255.255.255.224
        #         gateway: 10.40.13.160
        #         dns: 10.40.1.80, 10.40.1.81
        server = socket.inet_aton('10.40.13.161')
        pkt += struct.pack('!BB4s', DHCP_SERVER, 4, server)
        #mask = socket.inet_aton(self.netconfig['mask'])
        mask = socket.inet_aton('255.255.255.224')
        pkt += struct.pack('!BB4s', DHCP_IP_MASK, 4, mask)
        pkt += struct.pack('!BB4s', DHCP_IP_GATEWAY, 4, server)
        # FIXME: Serving only default DNS for now
        dns = self.config.get_bootp_default_dns()

        if dns:
            if dns.lower() == 'auto':
                dns = self.get_dns_server() or socket.inet_ntoa(server)
            dns = socket.inet_aton(dns)
            pkt += struct.pack('!BB4s', DHCP_IP_DNS, 4, dns)
        pkt += struct.pack('!BBI', DHCP_LEASE_TIME, 4,
                           int(self.config.get_bootp_default_lease_time()))
        pkt += struct.pack('!BB', DHCP_END, 0)

        # do not attempt to produce a PXE-augmented response for
        # regular DHCP requests
        if pxe:
            extra_buf = self.build_pxe_options(options, server)
            if not extra_buf:
                return
        else:
            extra_buf = self.build_dhcp_options(hostname)

        # update the UUID cache
        if pxe:
            self.uuidpool[mac_addr] = uuid

        # send the response
        if gi_addr:
            sock.sendto(pkt + extra_buf, (gi_str, 67))
        else:
            sock.sendto(pkt + extra_buf, addr)

        # update the current state
        if currentstate != newstate:
            self.log.info('Moving from state %d to state %d' % \
                            (currentstate, newstate))
            self.states[mac_str] = newstate
Exemple #8
0
    def handle(self, sock, addr, data):
        sender = addr
        self.log.info('Sender: %s on socket %s' % (addr, sock.getsockname()))
        if len(data) < DHCPFormatSize:
            self.log.error('Cannot be a DHCP or BOOTP request - too small!')
        tail = data[DHCPFormatSize:]
        buf = list(struct.unpack(DHCPFormat, data[:DHCPFormatSize]))
        if buf[BOOTP_OP] != BOOTREQUEST:
            self.log.warn('Not a BOOTREQUEST')
            return
        options = self.parse_options(tail)
        if options is None:
            self.log.warn('Error in option parsing, ignore request')
            return

        # Extras (DHCP options)
        try:
            dhcp_msg_type = ord(options[53][0])
        except KeyError:
            dhcp_msg_type = None

        server_addr = self.netconfig['address']
        mac_addr = buf[BOOTP_CHADDR][:6]
        gi_addr = buf[BOOTP_GIADDR][:4]
        mac_str = ':'.join(['%02X' % ord(x) for x in mac_addr])
        gi_str = '.'.join(['%d' % ord(x) for x in gi_addr])
        self.log.debug("Gateway address: %s" % gi_str)
        # is the UUID received (PXE mode)
        if 97 in options and len(options[97]) == 17:
            uuid = options[97][1:]
            pxe = True
            self.log.info('PXE UUID has been received')
        # or retrieved from the cache (DHCP mode)
        else:
            uuid = self.uuidpool.get(mac_addr, None)
            pxe = False
            self.log.info('PXE UUID not present in request')
        uuid_str = uuid and ('%s-%s-%s-%s-%s' % \
            tuple([hexlify(x) for x in uuid[0:4], uuid[4:6], uuid[6:8],
                                       uuid[8:10], uuid[10:16]])).upper()
        if uuid_str:
            self.log.info('UUID is %s for MAC %s' % (uuid_str, mac_str))

        hostname = ''
        filename = ''

        # Basic state machine
        currentstate = self.states.setdefault(mac_str, self.ST_IDLE)
        newstate = currentstate
        if currentstate == self.ST_IDLE:
            if pxe and (dhcp_msg_type == DHCP_DISCOVER):
                # BIOS is booting up, and try to locate a DHCP server
                newstate = self.ST_PXE
        elif currentstate == self.ST_PXE:
            if not pxe and (dhcp_msg_type == DHCP_REQUEST):
                # OS is booting up, and confirm a previous DHCP dicovery
                newstate = self.ST_DHCP
        else:  # currentstate == self.ST_DHCP
            if pxe:
                # OS was running but the BIOS is performing a DHCP request:
                # board has been restarted
                newstate = self.ST_PXE

        # if the state has not evolved from idle, there is nothing to do
        if newstate == self.ST_IDLE:
            self.log.info('Request from %s ignored (idle state)' % mac_str)
            sdhcp = self.config.get_bootp_allow_simple_dhcp()
            simple_dhcp = sdhcp and to_bool(sdhcp)
            if not simple_dhcp:
                return

        # construct reply
        buf[BOOTP_OP] = BOOTREPLY
        self.log.info('Client IP: %s' % socket.inet_ntoa(buf[7]))
        if buf[BOOTP_CIADDR] == '\x00\x00\x00\x00':
            self.log.debug('Client needs its address')
            host_data = self.get_host_data_for_mac(mac_str)
            ipaddr = host_data['address']

            self.log.debug("IPADDR: {0}".format(ipaddr))
            if not ipaddr:
                self.log.error("Can't get IP address!")
                return
            ip = None
            if mac_str in self.ippool:
                ip = self.ippool[mac_str]
                self.log.info('Lease for MAC %s already defined as IP %s' % \
                                (mac_str, ip))
            else:
                self.ippool[mac_str] = ipaddr
                ip = ipaddr

            if not ip:
                #raise BootpError('No more IP available in definined pool')
                self.log.error("Can not find IP assigned to mac: %s" % mac_str)
                return

            mask = iptoint(self.netconfig['mask'])
            reply_broadcast = iptoint(ip) & mask
            reply_broadcast |= (~mask) & ((1 << 32) - 1)
            buf[BOOTP_YIADDR] = socket.inet_aton(ip)
            buf[BOOTP_SECS] = 0
            buf[BOOTP_FLAGS] = BOOTP_FLAGS_NONE
            addr = (inttoip(reply_broadcast), addr[1])
            self.log.debug('Reply to: %s:%s' % addr)
        else:
            buf[BOOTP_YIADDR] = buf[BOOTP_CIADDR]
            ip = socket.inet_ntoa(buf[BOOTP_YIADDR])
        buf[BOOTP_SIADDR] = socket.inet_aton(server_addr)
        if gi_addr:
            self.log.debug('Reply via gateway: %s' % gi_str)
            buf[BOOTP_GIADDR] = socket.inet_aton(gi_str)
        # sname
        buf[BOOTP_SNAME] = \
            '.'.join([host_data['hostname'], host_data['domain']])
        # file
        buf[BOOTP_FILE] = 'boot_file' in host_data and host_data[
            'boot_file'] or self.config.get_bootp_default_boot_file()

        if not dhcp_msg_type:
            self.log.warn('No DHCP message type found, discarding request')
            return
        if dhcp_msg_type == DHCP_DISCOVER:
            self.log.debug('DHCP DISCOVER')
            dhcp_reply = DHCP_OFFER
            self.log.info('Offering lease for MAC %s: IP %s' % \
                          (mac_str, ip))
        elif dhcp_msg_type == DHCP_REQUEST:
            self.log.debug('DHCP REQUEST')
            dhcp_reply = DHCP_ACK
            self.log.info('New lease for MAC %s: IP %s' % \
                          (mac_str, ip))
        elif dhcp_msg_type == DHCP_RELEASE:
            self.log.info('DHCP RELEASE')
            if not self.notify:
                return
        elif dhcp_msg_type == DHCP_INFORM:
            self.log.info('DHCP INFORM')
            return
        elif dhcp_msg_type == DHCP_DECLINE:
            self.log.debug('DHCP DECLINE')
            return
        else:
            self.log.error('Unmanaged DHCP message: %d' % dhcp_msg_type)
            return

        pkt = struct.pack(DHCPFormat, *buf)
        pkt += struct.pack('!BBB', DHCP_MSG, 1, dhcp_reply)
        #server = socket.inet_aton(server_addr)
        # FIXME: Hardcoded relay and netmask
        # Add something in lines of:
        # networks:
        #     10.40.13.160:
        #         netmask: 255.255.255.224
        #         gateway: 10.40.13.160
        #         dns: 10.40.1.80, 10.40.1.81
        server = socket.inet_aton('10.40.13.161')
        pkt += struct.pack('!BB4s', DHCP_SERVER, 4, server)
        #mask = socket.inet_aton(self.netconfig['mask'])
        mask = socket.inet_aton('255.255.255.224')
        pkt += struct.pack('!BB4s', DHCP_IP_MASK, 4, mask)
        pkt += struct.pack('!BB4s', DHCP_IP_GATEWAY, 4, server)
        # FIXME: Serving only default DNS for now
        dns = self.config.get_bootp_default_dns()

        if dns:
            if dns.lower() == 'auto':
                dns = self.get_dns_server() or socket.inet_ntoa(server)
            dns = socket.inet_aton(dns)
            pkt += struct.pack('!BB4s', DHCP_IP_DNS, 4, dns)
        pkt += struct.pack('!BBI', DHCP_LEASE_TIME, 4,
                           int(self.config.get_bootp_default_lease_time()))
        pkt += struct.pack('!BB', DHCP_END, 0)

        # do not attempt to produce a PXE-augmented response for
        # regular DHCP requests
        if pxe:
            extra_buf = self.build_pxe_options(options, server)
            if not extra_buf:
                return
        else:
            extra_buf = self.build_dhcp_options(hostname)

        # update the UUID cache
        if pxe:
            self.uuidpool[mac_addr] = uuid

        # send the response
        if gi_addr:
            sock.sendto(pkt + extra_buf, (gi_str, 67))
        else:
            sock.sendto(pkt + extra_buf, addr)

        # update the current state
        if currentstate != newstate:
            self.log.info('Moving from state %d to state %d' % \
                            (currentstate, newstate))
            self.states[mac_str] = newstate