def test_replace_ipv4_host_where_name_differs(tmpdir): """ Test replacement of an ipv4 entry where just the name differs """ hosts_file = tmpdir.mkdir("etc").join("hosts") hosts_file.write("82.132.132.132\texample.com\texample\n") hosts_entries = Hosts(path=hosts_file.strpath) new_entry = HostsEntry(entry_type='ipv4', address='82.132.132.132', names=['example2.com', 'example']) hosts_entries.add(entries=[new_entry], force=True) assert hosts_entries.exists(address='82.132.132.132') assert hosts_entries.exists(names=['example2.com', 'example'])
def test_addition_of_ipv4_entry_where_matching_exists_and_force_true(tmpdir): """ Test replacement of an ipv4 entry where just the address differs """ hosts_file = tmpdir.mkdir("etc").join("hosts") hosts_file.write("82.132.132.132\texample.com\texample\n") hosts_entries = Hosts(path=hosts_file.strpath) new_entry = HostsEntry(entry_type='ipv4', address='82.132.132.132', names=['something.com', 'example']) hosts_entries.add(entries=[new_entry], force=True) assert hosts_entries.exists(address='82.132.132.132') assert hosts_entries.exists(names=['something.com', 'example'])
def test_write_hosts_file(self): ''' test that adding and removing hosts modifies the hosts file correctly ''' temp_host_file = Hosts(self.temp_host_file.name) self.assertTrue(temp_host_file.exists(names=['hostess'])) self.assertFalse(temp_host_file.exists(names=['hostess2'])) watcher = hostess.Watcher(env=self.envvars) watcher.hostmap['hostess'] = True watcher.remove_host(fqdn='hostess') watcher.add_host(fqdn='hostess2', ip_addr='10.0.0.2') temp_host_file = Hosts(self.temp_host_file.name) self.assertFalse(temp_host_file.exists(names=['hostess'])) self.assertTrue(temp_host_file.exists(names=['hostess2']))
def test_add_adblock_entry_with_force_with_target_having_multiple_names(tmpdir): """ Test that an addition of an adblock entry replaces one with a matching name if force is True (multiple names) """ ipv4_line = '0.0.0.0 example.com example2.com' hosts_file = tmpdir.mkdir("etc").join("hosts") hosts_file.write(ipv4_line) hosts_entries = Hosts(path=hosts_file.strpath) assert hosts_entries.exists(address='0.0.0.0') new_entry = HostsEntry.str_to_hostentry('0.0.0.0 example.com example2.com') hosts_entries.add(entries=[new_entry], force=True) assert hosts_entries.exists(names=['example2.com'])
def test_remove_existing_ipv4_address_using_hostsentry(tmpdir): """ Test removal of an existing ip4 address """ ipv4_line = '1.2.3.4 example.com example' hosts_file = tmpdir.mkdir("etc").join("hosts") hosts_file.write(ipv4_line) hosts_entries = Hosts(path=hosts_file.strpath) assert hosts_entries.exists(address='1.2.3.4') assert hosts_entries.exists(names=['example.com']) hosts_entries.remove_all_matching(address='1.2.3.4', name='example.com') assert not hosts_entries.exists(address='1.2.3.4') assert not hosts_entries.exists(names=['example.com'])
def update_hosts_file(system_config: Config, warning_callback=lambda msg: None): """Update the hosts-file for the current project, if any is loaded and updating is enabled in configuration. The hosts file is written, if it was changed. If it can't be written, warning messages are send to the lambda that outputs how to manually change the host file. :param warning_callback: Callback that receives strings representing warning messages to output to users. :param system_config: System configuration """ if system_config["update_hosts_file"]: if "project" in system_config: hosts = Hosts() new_entries = [] changes = False base_url = system_config["proxy"]["url"] if not hosts.exists(names=[base_url]): changes = True new_entries.append( HostsEntry(entry_type='ipv4', address='127.0.0.1', names=[base_url])) if "services" in system_config["project"]["app"]: for service in system_config["project"]["app"][ "services"].values(): domain = service.domain() if not hosts.exists(names=[domain]): changes = True new_entries.append( HostsEntry(entry_type='ipv4', address='127.0.0.1', names=[domain])) hosts.add(new_entries) if changes: try: hosts.write() except UnableToWriteHosts: entries = "\n".join( [f"{e.address}\t{e.names[0]}" for e in new_entries]) warning_callback( f"Could not update the hosts-file ({hosts.hosts_path}) to configure proxy server routing.\n" f"> Give your user permission to edit this file, to remove this warning.\n" f"> If you wish to manually add the entries instead, " f"add the following entries to {hosts.hosts_path}:\n{entries}\n" )
def test_addition_of_ipv6_entry_where_matching_name_exists_and_force_false(tmpdir): """ Test no replacement of an ipv6 entry where the address is different but there is a matching name and force is false """ hosts_file = tmpdir.mkdir("etc").join("hosts") hosts_file.write("fe80::200:f8ff:fe21:67cf\texample.com\texample\n") hosts_entries = Hosts(path=hosts_file.strpath) new_entry = HostsEntry(entry_type='ipv6', address='2001:db8:a0b:12f0::1', names=['example.com', 'example']) hosts_entries.add(entries=[new_entry], force=False) assert not hosts_entries.exists(address='2001:db8:a0b:12f0::1') assert hosts_entries.exists(address='fe80::200:f8ff:fe21:67cf') assert hosts_entries.exists(names=new_entry.names)
def prepare_hosts(self): host = self.host_name if host: if self.machine_name: ip = self.machine.ip(machine=self.machine_name) else: ip = '127.0.0.1' self.logger.debug('Prepare hosts: {name} with {ip}'.format(name=host, ip=ip)) hosts = Hosts() for entry in hosts.entries: if entry.address == ip: if host not in entry.names: entry.names.append(host) entry.names = list(set(entry.names)) if not hosts.exists(names=[host]): entry = HostsEntry(entry_type='ipv4', address=ip, names=[host]) hosts.add(entries=[entry]) try: # make backup hosts_path = Hosts.determine_hosts_path() hosts_backup_path = hosts_path + '.' + datetime.datetime.today().strftime('%Y%m%d') shutil.copy(hosts_path, hosts_backup_path) except BaseException: pass try: hosts.write() except BaseException: self.logger.debug('Unable to write host file, ignored.')
def test_replacement_of_ipv4_entry_where_address_differs(tmpdir): """ Test replacement of an ipv4 entry where just the address differs Add: 82.132.132.132 example.com example Then add (with force): 82.132.132.133 example.com example The second addition should replace the former as there is an address match """ hosts_file = tmpdir.mkdir("etc").join("hosts") hosts_file.write("82.132.132.132\texample.com\texample\n") hosts_entries = Hosts(path=hosts_file.strpath) new_entry = HostsEntry(entry_type='ipv4', address='82.132.132.133', names=['example.com', 'example']) hosts_entries.add(entries=[new_entry], force=True) assert hosts_entries.exists(address='82.132.132.133') assert hosts_entries.exists(names=['example.com', 'example'])
class HostsFile(object): def __init__(self): self.hosts = Hosts() def verifyentry(self, ip, domains): # Check the hosts file for concurrency with the pickle file if(self.hosts.exists(address=ip) and self.hosts.exists(names=[domains])): return True else: return False def addentry(self, ip, domains): # Python-Hosts will support multiple domain entries # @ TO-DO add support for multiple domain entries new_entry = HostsEntry(entry_type='ipv4', address=ip, names=[domains]) self.hosts.add(new_entry) self.hosts.write()
def test_add_single_ipv6_host(tmpdir): """ Test addition of an ipv6 entry """ hosts_file = tmpdir.mkdir("etc").join("hosts") hosts_file.write("127.0.0.1\tlocalhost\n") hosts_entries = Hosts(path=hosts_file.strpath) new_entry = HostsEntry(entry_type='ipv6', address='::1', names=['localhost6.localdomain6', 'localhost6']) hosts_entries.add(entries=[new_entry], force=False) assert hosts_entries.exists(address='::1')
def test_add_single_ipv4_host(tmpdir): """ Test the addition of an ipv4 host succeeds """ hosts_file = tmpdir.mkdir("etc").join("hosts") hosts_file.write("127.0.0.1\tlocalhost\n") hosts = Hosts(path=hosts_file.strpath) new_entry = HostsEntry(entry_type='ipv4', address='123.123.123.123', names=['test.example.com']) hosts.add(entries=[new_entry]) assert hosts.exists(address='123.123.123.123')
def test_add_adblock_entry_without_force_multiple_names(tmpdir): """ Test that addition of an adblock entry does not succeed if force is not set and there is a matching name """ ipv4_line = '0.0.0.0 example2.com example3.com' hosts_file = tmpdir.mkdir("etc").join("hosts") hosts_file.write(ipv4_line) hosts_entries = Hosts(path=hosts_file.strpath) new_entry = HostsEntry.str_to_hostentry('0.0.0.0 example.com example3.com') hosts_entries.add(entries=[new_entry], force=False) assert hosts_entries.exists(names=['example2.com'])
def test_write_will_create_path_if_missing(): """ Test that the hosts file declared when constructing a Hosts instance will be created if it doesn't exist """ now = datetime.datetime.now() timestamp = now.strftime('%Y%m%d%H%M%S') hosts_path = '/tmp/testwrite.{0}'.format(timestamp) hosts = Hosts(path=hosts_path) entry = HostsEntry.str_to_hostentry('1.2.3.4 example.com example.org') hosts.add(entries=[entry]) hosts.write() hosts2 = Hosts(path=hosts_path) os.remove(hosts_path) assert hosts2.exists(address='1.2.3.4')
mac = client['mac'] if ip <> "Unknown": ip = IPAddress(ip) if ip <> "Unknown" and name <> None: name = name.replace(" ", "") list[ip] = name sorted(list) for entry in list.items(): ip = str(entry[0]) name = entry[1] new_entry = HostsEntry(entry_type='ipv4', address=ip, names=[name]) if hosts.exists(ip): hosts.remove_all_matching(ip) hosts.add([new_entry]) if args.verbose: print entry[0], '\t', entry[1] if args.verbose: if args.nohosts: print "--nohosts specified, not attempting to write to hosts file" if not args.nohosts: try: hosts.write() except: print "You need root permissions to write to /etc/hosts - skipping!"
class HostsHandler(): ''' handle the Hosts object and the individual HostEntry objects ''' block_start = '### dnsmasq updater start ###' def __init__(self, file_handler, **kwargs): self.params = SimpleNamespace(**kwargs) self.logger = get_logger(self.__class__.__name__, self.params.log_level) self.file_handler = file_handler self.temp_file = file_handler.temp_file self.delayed_write = ResettableTimer(self.params.local_write_delay, self.write_hosts) self.get_remote_hosts() def get_remote_hosts(self): ''' parse remote hosts file into python-hosts ''' self.hosts = Hosts(path='/dev/null') self.logger.debug('Cleaning remote hosts..') for line in self.file_handler.hosts: if self.block_start in line: break line_type = HostsEntry.get_entry_type(line) if line_type in ['ipv4', 'ipv6']: self.hosts.add([HostsEntry.str_to_hostentry(line)]) elif line_type == 'comment': self.hosts.add( [HostsEntry(entry_type='comment', comment=line)]) elif line_type == 'blank': # python_hosts.Hosts.add doesn't seem to work for blank lines. # We'll have to use the internal class methods directly. self.hosts.entries.append(HostsEntry(entry_type="blank")) else: self.logger.warning('Unknown line type in hosts file: %s', line) self.hosts.add( [HostsEntry(entry_type='comment', comment=self.block_start)]) if self.params.log_level == logging.DEBUG: self.logger.debug('Cleaned remote hosts:') for entry in self.hosts.entries: print(' ', entry) def parse_hostnames(self, hostnames): ''' return dictionary items containing IPs and a list of hostnames dict_items([ ('<IP_1>', ['<hostname1>', '<hostname2>', etc..]), ('<IP_2>', ['<hostname3>', '<hostname4>', etc..]), etc..]) ''' hostname_dict = defaultdict(set) for hostname in hostnames: host_ip = self.params.ip if ':' in hostname: hostname, host_ip = hostname.split(':', 1) try: hostname = hostname[0:hostname.index('.' + self.params.domain)] except ValueError: pass if not self.hosts.exists(names=[hostname]): hostname_dict[host_ip].update( [hostname, hostname + '.' + self.params.domain]) return dict([key, sorted(value)] for key, value in hostname_dict.items()) def add_hosts(self, hostnames, do_write=True): ''' create HostsEntry for a host and add it to Hosts object, optionally write out ''' parsed_hostnames = self.parse_hostnames(hostnames) parsed_items = parsed_hostnames.items() if parsed_items: for host_ip, names in parsed_items: self.logger.debug('Adding: (%s) %s', host_ip, names) hostentry = HostsEntry(entry_type='ipv4', address=host_ip, names=names) self.hosts.add([hostentry], force=True, allow_address_duplication=True) if do_write: self.queue_write() self.logger.info('Added host(s): %s', sum(parsed_hostnames.values(), [])) else: self.logger.info('Host already exists, nothing to add.') return parsed_items def del_hosts(self, hostnames): ''' delete hostnames, optionally write out ''' self.logger.debug('Deleting hostnames: %s', hostnames) for hostname in hostnames: try: hostname = hostname[0:hostname.index(':')] except ValueError: pass self.hosts.remove_all_matching(name=hostname) self.queue_write() def queue_write(self): ''' delayed writing of the local and remote hosts files the delay allows for any additional changes in the immediate future, such as expected when a container is restarting, for example. ''' self.delayed_write.reset() def write_hosts(self): ''' write local hosts file, put it on the remote device ''' if self.params.log_level == logging.DEBUG: self.logger.debug('Writing local hosts temp file: %s', self.temp_file.name) for entry in self.hosts.entries: print(' ', entry) self.hosts.write(path=self.temp_file.name) self.temp_file.seek(0) self.file_handler.queue_put()
ipaddress = nm[host]['addresses']['ipv4'] macaddress = nm[host]['addresses']['mac'] if macaddress in addressList: etchostname = addressList[macaddress] print( f"Device at {ipaddress} ({macaddress}) is in our list as {etchostname}" ) else: print( f"Device at {ipaddress} ({macaddress}) is NOT in our list." ) break # if neither the hostname or ip address exist in hosts file if not hosts.exists(ipaddress, etchostname): print( f"Adding hostname: {etchostname} with {ipaddress} to hosts file." ) hosts.remove_all_matching(name=etchostname) new_entry = HostsEntry(entry_type='ipv4', address=ipaddress, names=[etchostname]) hosts.add([new_entry]) # if the hostname exists but ip address in hosts file differs from nmap scan for entry in hosts.entries: if entry.entry_type in ['ipv4', 'ipv6']: if entry.names[0] == etchostname: if entry.address != ipaddress: print(