I am trying to manage a host file with a python script. I am new to python and I am having a hard time with figuring out how to replace a line if I find a match. For example, if the address gets changed in a host file for a website I want the script to find it and change it back. Thanks for your help.
import os
import time
#location to the host file to read and write to
hosts_path=r"C:\Windows\System32\drivers\etc\hosts"
#the address I want for the sites
redirect="0.0.0.0"
#the websites that I will set the address for
website_list=["portal.citidirect.com","www.bcinet.nc","secure.banque-tahiti.pf","www.bancatlan.hn","www.bancentro.com.ni","www.davivienda.com.sv","www.davivienda.cr","cmo.cibc.com","www.bi.com.gt","empresas.banistmo.com","online.belizebank.com","online.westernunion.com","archive.clickatell.com"]
#continuous loop
while True:
with open(hosts_path,'r+') as file:
content=file.read()
#for each of the websites in the list above make sure they are in the host file with the correct address
for website in website_list:
site=redirect+" "+ website
#here is where I have an issue, if the website is in the host file but with the wrong address I want to write over the line, instead the program is adding it to the end of the file
if website in content:
if site in content:
pass
else:
file.write(site)
else:
file.write("\n"+site)
time.sleep(300)
os.system('ipconfig /flushdns')
You need to read the file into a list, then changes the index of the list if it needs to be, then writes the list back to the file. What you are doing was just writing to the end of the file. You can’t change a file directly like that. You need to record the changes in a list then write the list. I ended up having to re-write a lot of the code. Here's the full script. I wasn't sure what the os.system('ipconfig /flushdns') was accomplishing, so I removed it. You can easily add it back where you want.
#!/usr/bin/env python3.6
import time
hosts_path = r"C:\\Windows\\System32\\drivers\\etc\\hosts"
redirect = "0.0.0.0"
website_list = [
"portal.citidirect.com",
"www.bcinet.nc",
"secure.banque-tahiti.pf",
"www.bancatlan.hn",
"www.bancentro.com.ni",
"www.davivienda.com.sv",
"www.davivienda.cr",
"cmo.cibc.com",
"www.bi.com.gt",
"empresas.banistmo.com",
"online.belizebank.com",
"online.westernunion.com",
"archive.clickatell.com"]
def substring_in_list(the_list, substring):
for s in the_list:
if substring in s:
return True
return False
def write_websites():
with open(hosts_path, 'r') as file:
content = file.readlines()
for website in website_list:
site = "{} {}\n".format(redirect, website)
if not substring_in_list(content, website):
content.append(site)
else:
for line in content:
if site in line:
pass
elif website in line:
line = site
with open(hosts_path, "w") as file:
file.writelines(content)
while True:
write_websites()
time.sleep(300)
So, you're going to assign the same IP address to every site that doesn't appear in your websites list?
The following would replace what's inside your outermost while loop:
# Read in all the lines from the host file,
# splitting each into hostname, IPaddr and aliases (if any),
# and trimming off leading and trailing whitespace from
# each of these components.
host_lines = [[component.strip() for component in line.split(None, 2)] for line in open(host_path).readlines()]
# Process each of the original lines.
for line in host_lines:
# Is the site in our list?
if line[1] in website_list:
# Make sure the address is correct ...
if line[0] != redirect:
line[0] == redirect
# We can remove this from the websites list.
website_list.remove(line[1])
# Whatever sites are left in websites don't appear
# in the hosts file. Add lines for these to host_lines
host_lines.extend([[redirect, site] for site in website_list])
# Write the host_lines back out to the hosts file:
open(hosts_path, 'w').write("\n".join([" ".join(line) for line in host_lines]))
The rightmost join glues the components of each line back together into a single string. The join to the left of it glues all of these strings together with newline characters between them, and writes this entire string to the file.
I have to say, this looks like a rather complicated and even dangerous way to make sure your hosts file stays up-to-date and accurate. Wouldn't it be better to just have a cron job scp a known-good hosts file from a trusted host every five minutes instead?
I ended up mixing some of the responses to create a new file to replace the current host file using functions as shown below. In addition to this code I am using pyinstaller to turn it into an exe then I setup that exe to run as a auto-start service.
#!/usr/bin/env python3.6
import os
import shutil
import time
temp_file = r"c:\temp\Web\hosts"
temp_directory="c:\temp\Web"
hosts_path = r"C:\Windows\System32\drivers\etc\hosts"
websites = ('''# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host
# localhost name resolution is handled within DNS itself.
# 127.0.0.1 localhost
# ::1 localhost
0.0.0.0 portal.citidirect.com
0.0.0.0 www.bcinet.nc
0.0.0.0 secure.banque-tahiti.pf
0.0.0.0 www.bancatlan.hn
0.0.0.0 www.bancentro.com.ni
0.0.0.0 www.davivienda.com.sv
0.0.0.0 www.davivienda.cr
0.0.0.0 cmo.cibc.com
0.0.0.0 www.bi.com.gt
0.0.0.0 empresas.banistmo.com
0.0.0.0 online.belizebank.com
0.0.0.0 online.westernunion.com
0.0.0.0 archive.clickatell.com''')
def write_websites():
with open(temp_file, 'w+') as file:
file.write(websites)
while True:
if not os.path.exists(temp_directory):
os.makedirs(temp_directory)
try:
os.remove(temp_file)
except OSError:
pass
write_websites()
try:
os.remove(hosts_path)
except OSError:
pass
try:
shutil.move(temp_file,hosts_path)
except OSError:
pass
os.system('ipconfig /flushdns')
time.sleep(300)
Related
I have some code that will scan for wireless packets and displays the mac address from each of them. What i would like to do is have a text file of mac addresses and for the code to alert me with a message when one of the addresses in the file is picked up on the wireless scan. I can not think of a way to implement this, here is the code for the wiresless scan and below is an example of the text file.
import sys
from scapy.all import *
devices = set()
def PacketHandler(pkt):
if pkt.haslayer(Dot11):
dot11_layer = pkt.getlayer(Dot11)
if dot11_layer.addr2 and (dot11_layer.addr2 not in devices):
devices.add(dot11_layer.addr2)
print dot11_layer.addr2
sniff(iface = sys.argv[1], count = int(sys.argv[2]), prn = PacketHandler)
here is example of the text file.
00:11:22:33:44:55
AA:BB:CC:DD:EE:FF
Create a function that reads from a .txt and store each line (matching a MAC address) in a list.
def getListMac() -> list: # you can put the path for your .txt file as argument
with open('MAClist.txt', 'r+') as file:
res = [x.rstrip('\n') for x in file.readlines()]
return res
And then check in your packetHandler function if the mac if in this list.
Here you have two choice :
Call getListMac() at the start of your program, store it in a global variable. Go for this if your .txt file won't change after launching your program.
MACLIST = getListMac()
...
# in your PacketHandler function
if mac in MACLIST:
print("mac found!") #or whatever your want to do
Call the function each time a packet is sniffed. Go for this option if the list of MAC addresses frequently changes and you need it updated when your program is running. Be careful with it as this will slow your program, especially if your list is very long.
# in your PacketHandler function:
if mac in getListMac():
print("mac found!") # or whatever your want to do
Finally, i will finish this post by advising you to use a real DBMS, which will be much more efficient than reading a txt file. ;)
EDIT
To answer your comment :
Modify the getListMac function in order to store the information in a dictionnary.
Here is an exemple assuming you use " - " as separator between MAC - Time - Username
def getListMac() -> dict: # you can put the path for your .txt file as argument
with open('MAClist.txt', 'r+') as file:
res = {x.rstrip('\n').split(" - ")[0]: x.rstrip('\n').split(" - ")[2] for x in file.readlines()}
return res
Access the data in the dictionary like this:
if MAC in MACLIST:
print(f"MAC found -> {MAC}, Username -> {MACLIST[MAC]}")
Willing to add wifi connections from a kivy app and I'm using a simple function to edit wpa_supplicant.conf file adding there new networks.
My function correctly writes the configuration there and seems identical to the configs aded through raspbian GUI...
But when I reboot the raspberry, it says no networks interfaces were found but it get solved if I delete the last added lines from the wpa_supplicant.conf file. For some reasons raspbian fails to read properly this file after the edit, but I don't see what I'm doing wrong here which defers from the default configurations.
Hope someone can provide me some hint... I run the script as sudo, so can't be any permission issues, I tried to look into any diferences in the way I write the config and the config provided by raspbian, but no clue...
Here you can see the code:
def CreateWifiConfig(SSID, password):
config = (
'\nnetwork={{\n' +
'\tssid="{}"\n' +
'\tpsk="{}"\n' + '}}').format(SSID, password)
print(config)
with open("/etc/wpa_supplicant/wpa_supplicant.conf", "a+") as wifi:
wifi.write(config)
wifi.close()
print("Wifi config added")```
This is just a drive-by comment - I've not run your code, I'm just interpreting it based on what I'm reading - but a couple of things strike me here:
1) I don't see a key_mgmt value in your config. Usually this is like WPA-PSK, but you can see some addtional possible values here
2) Because you're using the "with" statement, the file should be automatically closed for you (you shouldn't need to call close() on it a second time).
3) The way you're constructing the config string looks a little strange to me, how about something like this (totally subjective, just a bit more readable to my eyes):
def CreateWifiConfig(SSID, password):
config_lines = [
'\n',
'network={',
'\tssid="{}"'.format(SSID),
'\tpsk="{}"'.format(password),
'\tkey_mgmt=WPA-PSK',
'}'
]
config = '\n'.join(config_lines)
print(config)
with open("/etc/wpa_supplicant/wpa_supplicant.conf", "a+") as wifi:
wifi.write(config)
print("Wifi config added")
4) The other thing to note here is that this code is not idempotent - you'll not be able to run this multiple times without compromising the integrity of the file content. You're probably aware of that already and may not especially care, but just pointing it out anyway.
Hopefully the missing key_mgmt is all it is.
this is my solution to add or update wifi.
The json argument in the method is a dictionary with value:
{"ssid": "wifi_name", "psk": "password"}. This script can be easily modified to add id_str or priority to a networks.
def command_add_wifi(json):
print("-> Adding wifi")
# Read file WPA suppliant
networks = []
with open("/etc/wpa_supplicant/wpa_supplicant.conf", "r") as f:
in_lines = f.readlines()
# Discover networks
out_lines = []
networks = []
i = 0
isInside = False
for line in in_lines:
if "network={" == line.strip().replace(" ", ""):
networks.append({})
isInside = True
elif "}" == line.strip().replace(" ", ""):
i += 1
isInside = False
elif isInside:
key_value = line.strip().split("=")
networks[i][key_value[0]] = key_value[1]
else:
out_lines.append(line)
# Update password or add new
isFound = False
for network in networks:
if network["ssid"] == f"\"{json['ssid']}\"":
network["psk"] = f"\"{json['psk']}\""
isFound = True
break
if not isFound:
networks.append({
'ssid': f"\"{json['ssid']}\"",
'psk': f"\"{json['psk']}\"",
'key_mgmt': "WPA-PSK"
})
# Generate new WPA Supplicant
for network in networks:
out_lines.append("network={\n")
for key, value in network.items():
out_lines.append(f" {key}={value}\n")
out_lines.append("}\n\n")
# Write to WPA Supplicant
with open('/etc/wpa_supplicant/wpa_supplicant.conf', 'w') as f:
for line in out_lines:
f.write(line)
print("-> Wifi added !")
I tried rewriting the 'wpa_supplicant.conf' file using a Python script and the whole Wi-Fi system just broke down, and I have to reformat and reinstall Raspbian OS on the SD card all over again. Creating a new 'wpa_supplicant.conf' file in the boot drive of the SD card doesn't work either. Luckily, I found a solution to connect to a new network using a Python script, but before that, you'll need to follow these steps first.
Solution: Instead of rewriting 'wpa_supplicant.conf' using with open('/etc/wpa_supplicant/wpa_supplicant.conf', 'w') as file:, rewrite the 'interfaces' file from the /etc/network/interfaces path.
Add this code below the source-directory /etc/network/interfaces.d line of the 'interfaces' file:
auto wlan0
iface wlan0 inet dhcp
wpa-ssid "WIFI NETWORK NAME HERE"
wpa-psk "WIFI NETWORK PASSWORD HERE"
Save the 'interfaces' file and open the 'wpa_supplicant.conf' file.
Add update_config=1 between the lines of ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev and network={.... From my observation, this kinda ignores the contents of network={... and divert its retrieval of Wi-Fi information to the /etc/network/interfaces file.
Save the file and reboot.
Once rebooted, you can rewrite the /etc/network/interfaces file by executing a Python script whenever you want to change to a new network (the script must lead to a system reboot at the end in order for the new Wi-Fi changes to take effect). (I don't know whether the 'interfaces' file allows multiple networks to be added into, so far I only tested with one network at a time, since this has already fulfilled my project goal.) Here's a Python code sample to change the network information in the 'interfaces' file:
import os
import time
SSID = input('Enter SSID: ')
password = input("Enter password: ")
with open('/etc/network/interfaces', 'w') as file:
content = \
'# interfaces(5) file used by ifup(8) and ifdown(8)\n\n' + \
'# Please note that this file is written to be used with dhcpcd\n' + \
"# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'\n" + \
'# Include files from /etc/network/interfaces.d:\n' + \
'source-directory /etc/network/interfaces.d\n' + \
'auto wlan0\n' + \
'iface wlan0 inet dhcp\n' + \
'wpa-ssid "' + SSID + '"\n' + \
'wpa-psk "' + password + '"\n'
file.write(content)
print("Write successful. Rebooting now.")
time.sleep(2)
os.system('sudo reboot now')
Currently I have a text file with mutiple IP's I am currently attempting to pull only the domain name from the set of information given using nslookup (code below)
with open('test.txt','r') as f:
for line in f:
print os.system('nslookup' + " " + line)
This works in so far that it pulls all the information from the first IP's. I can't get it passed the first IP but I'm currently attempting to clean up the information recived to only the Domain name of the IP. Is there any way to do that or do I need to use a diffrent module
Like IgorN, I wouldn't make a system call to use nslookup; I would also use socket. However, the answer shared by IgorN provides the hostname. The requestor asked for the domain name. See below:
import socket
with open('test.txt', 'r') as f:
for ip in f:
fqdn = socket.gethostbyaddr(ip) # Generates a tuple in the form of: ('server.example.com', [], ['127.0.0.1'])
domain = '.'.join(fqdn[0].split('.')[1:])
print(domain)
Assuming that test.txt contains the following line, which resolves to a FQDN of server.example.com:
127.0.0.1
this will generate the following output:
example.com
which is what (I believe) the OP desires.
import socket
name = socket.gethostbyaddr(‘127.0.0.1’)
print(name) #to get the triple
print(name[0]) #to just get the hostname
I'm trying to filter certain packets with protocols using user input from a given pcap file and than move the packets to a new pcap file.
That the code I made so far:
# ===================================================
# Imports
# ===================================================
from scapy.all import *
from scapy.utils import PcapWriter
"""
your going to need to install the modules below
"""
from Tkinter import Tk
from tkFileDialog import askopenfilename
# ===================================================
# Constants
# ===================================================
#OS commands:
#~~~~~~~~~~~~~
if "linux2" in sys.platform:
"""
linux based system clear command
"""
CLEAR_COMMAND = "clear"
elif "win32" in sys.platform:
"""
windows based system clear command
"""
CLEAR_COMMAND = "cls"
elif "cygwin" in sys.platform:
"""
crygwin based clear command
"""
CLEAR_COMMAND = "printf \"\\033c\""
elif "darwin" in sys.platform:
"""
mac OS X based clear command
"""
CLEAR_COMMAND = "printf \'\\33c\\e[3J\'"
#Usage string:
#~~~~~~~~~~~~~~
FILE_STRING = "please choose a pcap file to use"
BROWSE_STRING = "press any key to browser files\n"
BAD_PATH_STRING = "bad file please try agien\n"
BAD_INPUT_STRING = "bad input please try agien\n"
PROTOCOL_STRING = "please enter the protocol you wish to filter\n"
NAME_STRING = "please enter the new pcap file name\n"
# ===================================================
# Code
# ===================================================
def filter_pcap():
"""
filtering from the given pcap file a protocol the user chooce (from any layer in the OSI model)
and than asks for a new pcap file name, than filters the given protocol to a new pcap file
:param none
:return nothing:
"""
path = file_browse()
i = 0
filtertype = raw_input(PROTOCOL_STRING)
name = raw_input(NAME_STRING)
packs = rdpcap(path)
for i in range(len(packs)):
if filtertype in packs[i]:
wrpcap(name +".pcap", packs[i])
def file_browse():
"""
Purpose: It will allow the user to browse files on his computer
than it will check if the path is ok and will return it
:returns - the path to the chosen pcap file
"""
path = "test"
while ".pcap" not in path:
print FILE_STRING
raw_input(BROWSE_STRING)
os.system(CLEAR_COMMAND)
Tk().withdraw()
path = askopenfilename()
if ".pcap" not in path:
print BAD_PATH_STRING
return path
filter_pcap()
Now the problem is that I'm failing to filter the packets correctly.
The code need to filter protocols from any layer and any kind.
I have checked that thread: How can I filter a pcap file by specific protocol using python?
But as you can see it was not answered and the user added the problems I had in the edit, if any one could help me it would be great
Example for how it should work:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lets say i use the file "sniff" as my first pcap file and it has 489 packets when 200 from those packets are http packets.
now there is that print:
please enter the protocol you wish to filter
'http'
and than there is the print:
please enter the new pcap file name
'new'
the user input was 'http' now the program will search for every packet that run on http protocol and will create a new pcap file called 'new.pcap'.
the file 'new.pcap' will contain 200 http packets.
now that thing should work with any protocol on the OSI model including protocols like IP, TCP, Ethernet and so on (all the protocols in the ascii model).
I have found out that wireshark command line has the option -R and tshark has .protocols, but it dont really work... Can any one check that?
edit: i found pyshark but i dont know how to write with it
I don't believe that scapy has any functions or methods to support application layer protocols in the way that you are after. However, using sport and dport as a filter will do the trick (provided you are going to see/are expecting default ports).
Try something like this:
def filter_pcap(filtertype = None):
..... snip .....
# Static Dict of port to protocol values. Like so:
protocols = {'http': 80, 'ssh': 22, 'telnet': 21}
# Check to see if it is in the list
while filtertype not in protocols:
filtertype = raw_input(PROTOCOL_STRING)
# Name for output file
name = raw_input(NAME_STRING)
# Read Input File
packs = rdpcap(path)
# Filters to only TCP packets
for packet in packs[TCP]:
# Filter only the proto (aka Port) that we want
if protocols[filtertype] in packet.sport or protocols[filtertype] in packet.dport :
# Write to file
wrpcap(name +".pcap", packet)
I am trying to create a cisco basic config based in a full config file.
Following some examples of the full file configuration:
!
policy-map QOS
class GOLD
priority percent 10
class SILVER
bandwidth 30
random-detect
class default
!
interface Loopback1
description Management
ip address 9.9.9.9 255.255.255.255
!
interface FastEthernet0/0
description LAN
ip address 6.6.6.6 255.255.255.0
!
ip access-list standard customer_internal
permit 1.1.1.1
permit 2.2.2.2
permit 3.3.3.3
!
I found out this ciscoconfparse library (https://pypi.python.org/pypi/ciscoconfparse). and was able to grab the configuration lines blocks to another file, but don´t know how to exclude the blocks to a basic config file.
from ciscoconfparse import CiscoConfParse
full_config_for_parse = file('./fullconfig.txt')
basic_config_file = open('./basic_config.txt', 'w') # This file needs to contain only basic config, like interface, IP, etc...
security_config_file = open('./security_config_file.txt', 'w') # This is the file that was able to send the line blocks
parse = CiscoConfParse(full_config_for_parse)
class_map = parse.find_all_children('class-map')
access_list = parse.find_all_children('ip access-list')
if class_map != ' ': # If class_map is not empty, it means that the full config file has class-map configuration, so, it needs to be removed or not copied to basic config file
for line in class_map:
security_config_file.write(line) # separating the blocks to another file
#basic_config_file.write(remove_this_line) I need to delete/not write this line to basic_config_file
if access_list != ' ':
for line in access_list:
security_config_file.write(line)
#basic_config_file.write(remove_this_line)
# There is another code part that is copying all the rest of the basic configuration to basic_config_file, that is working OK
files.close()
Anyone knows a better way for deleting or not copying these config blocks to a basic config file?
As far as I can tell, you want to delete policy-map and ip access-list from the configuration at the bottom of my answer, and save the result as basic_config.txt.
This is the most efficient way to do it...
from ciscoconfparse import CiscoConfParse
parse = CiscoConfParse('fullconfig.txt')
objs = list()
objs.extend(parse.find_objects(r'^policy-map')) # Append policy-map obj
objs.extend(parse.find_objects(r'ip\saccess-list'))# Append ip access-list obj
for obj in objs:
# When you delete a parent obj, it recurses through all children
obj.delete()
parse.commit()
parse.save_as('basic_config.txt') # Save the new configuration
When you look at basic_config.txt, it will have the following lines...
!
!
interface Loopback1
description Management
ip address 9.9.9.9 255.255.255.255
!
interface FastEthernet0/0
description LAN
ip address 6.6.6.6 255.255.255.0
!
!
File name: fullconfig.txt...
!
policy-map QOS
class GOLD
priority percent 10
class SILVER
bandwidth 30
random-detect
class default
!
interface Loopback1
description Management
ip address 9.9.9.9 255.255.255.255
!
interface FastEthernet0/0
description LAN
ip address 6.6.6.6 255.255.255.0
!
ip access-list standard customer_internal
permit 1.1.1.1
permit 2.2.2.2
permit 3.3.3.3
!
After a lot of hours of researches and tries, got what I want, editing the answer with new code that is now working:
from ciscoconfparse import CiscoConfParse
def main():
# 2nd Part - Begin
p = CiscoConfParse("./basic_config.txt")
basic_config_NEW = open('./basic_config_NEW.txt', 'w') # Need to open a new file as using the same one was getting empty file
for obj in p.find_objects(r'^class-map'):
obj.delete('class')
for obj in p.find_objects(r'^ip access-list'):
obj.delete('ip access-list')
for line in p.ioscfg:
basic_config_NEW.write(line) # This was adding the lines without break lines on the file
basic_config_NEW.write('\n') # Have to add it not sure if there is another way of doing it in one single line
basic_config_NEW.close()
# 2nd Part - End
if __name__ == "__main__":
main()