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)
'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')
'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')
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))
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)
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
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
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