def deconfigure_dhcp(self, interface): with self.dhcp_lock: client = self.dhcp_clients[interface] client.release() client.stop() del self.dhcp_clients[interface]
def configure_dhcp(self, interface, block=False, timeout=None): if interface in self.dhcp_clients: self.logger.info('Interface {0} already configured by DHCP'.format(interface)) return True def bind(old_lease, lease): self.logger.info('{0} DHCP lease on {1} from {2}, valid for {3} seconds'.format( 'Renewed' if old_lease else 'Acquired', interface, client.server_address, lease.lifetime, interface )) if old_lease is None or lease.client_ip != old_lease.client_ip: self.logger.info('Assigning IP address {0} to interface {1}'.format(lease.client_ip, interface)) alias = lease.client_interface iface = netif.get_interface(interface) if old_lease: try: addr = first_or_default(lambda a: a.address == old_lease.client_ip, iface.addresses) if addr: iface.remove_address(addr) except OSError as err: self.logger.error('Cannot remove alias {0}: {1}'.format(old_lease.client_ip, err.strerror)) try: iface.add_address(netif.InterfaceAddress(netif.AddressFamily.INET, alias)) except OSError as err: self.logger.error('Cannot add alias to {0}: {1}'.format(interface, err.strerror)) if lease.router and self.configstore.get('network.dhcp.assign_gateway'): try: rtable = netif.RoutingTable() newroute = default_route(lease.router) if rtable.default_route_ipv4 != newroute: if rtable.default_route_ipv4: self.logger.info('DHCP default route changed from {0} to {1}'.format( rtable.default_route_ipv4, newroute )) rtable.delete(rtable.default_route_ipv4) rtable.add(default_route(lease.router)) else: self.logger.info('Adding default route via {0}'.format(lease.router)) rtable.add(default_route(lease.router)) except OSError as err: self.logger.error('Cannot configure default route: {0}'.format(err.strerror)) if lease.dns_addresses and self.configstore.get('network.dhcp.assign_dns'): inp = [] addrs = [] proc = subprocess.Popen( ['/sbin/resolvconf', '-a', interface], stdout=subprocess.PIPE, stdin=subprocess.PIPE ) for i in lease.dns_addresses: # Filter out bogus DNS server addresses if str(i) in ('127.0.0.1', '0.0.0.0', '255.255.255.255'): continue inp.append('nameserver {0}'.format(i)) addrs.append(i) if lease.domain_name: inp.append('search {0}'.format(lease.domain_name)) proc.communicate('\n'.join(inp).encode('ascii')) proc.wait() self.client.emit_event('network.dns.configured', { 'addresses': addrs, }) self.logger.info('Updated DNS configuration') else: subprocess.call(['/sbin/resolvconf', '-d', interface]) self.client.emit_event('network.dns.configured', { 'addresses': [], }) self.logger.info('Deleted DNS configuration') def reject(reason): self.logger.info('DHCP request rejected on {0}: {1}'.format(interface, reason)) self.deconfigure_dhcp(interface) if not block: t = threading.Timer(60, self.configure_dhcp, args=(interface,)) t.start() def unbind(lease, reason): reasons = { dhcp.client.UnbindReason.EXPIRE: 'expired', dhcp.client.UnbindReason.REVOKE: 'revoked' } self.logger.info('DHCP lease on {0}: {1}'.format(interface, reasons.get(reason, 'revoked'))) def state_change(state): self.client.emit_event('network.interface.changed', { 'operation': 'update', 'ids': [interface] }) self.client.emit_event('network.changed', { 'operation': 'update' }) with self.dhcp_lock: client = dhcp.client.Client(interface, lambda: socket.gethostname().split('.')[0]) client.on_bind = bind client.on_unbind = unbind client.on_reject = reject client.on_state_change = state_change client.start() self.dhcp_clients[interface] = client if block: ret = client.wait_for_bind(timeout) if ret is None: client.stop() del self.dhcp_clients[interface] return ret is not None return True