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()
Related
I want to replace the IP addresses in a given PCAP file with Scapy.
The PCAP file (e.g. eth0.pcap) contains captures by Wireshark.
My message is not code, it shows the data flow between 2 IP addresses. I want to replace the original 2 addresses with another 2 addresses.
Example
Given before:
message1: 192.168.10.10-->192.168.20.20
message2: 192.168.20.20-->192.168.10.10
I want to replace for all packages within the file:
192.168.10.10 (source of first package) with 8.8.8.8
and 192.168.20.20 (destination of first package) with 1.1.1.1
So that afterwards there are:
message1: 172.10.10.10-->172.10.20.20
message2: 172.10.20.20-->172.10.10.10
How can I do this with?
hc_dev's answer guided me towards the solution.
I tried to understand it and make it work in my issue.
Below is my code:
from scapy.all import *
from scapy.utils import PcapWriter
packets = rdpcap('ftp.pcap')
new_cap = PcapWriter("ftp_new.pcap")
srcIp=packets[0][IP].src
dstIP=packets[0][IP].dst
#define new ip address I want use
ip1='8.8.8.8'
ip2='1.1.1.1'
#replace orinigal address
for p in packets:
if(p[IP].src == srcIp):
p[IP].src = ip1
elif(p[IP].src == dstIP):
p[IP].src = ip2
if(p[IP].dst == srcIp):
p[IP].dst = ip1
elif(p[IP].dst == dstIP):
p[IP].dst = ip2
new_cap.write(p)
wrpcap("ftp_new.pcap", packets)
So you want to modify packet capture output, like in PCAP file format.
This format is used by libpcap library to record captured packets to a file.
Scapy can read and write PCAP files, see the Scapy docs for PCAP.
Read, write, print, replace
To replace the IP addresses within this file, you have to read its packets into an object-model using the rdpcap() function.
Then you can print the IP addresses for each packet (with desired replacement).
Or you can also replace the IP within the object-model in memory.
Then write the complete model back using the wrpcap() function.
Example to print IP addresses
I used the example PCAP file dhcp.pcap from PCAP to Mermaid parser on GitHub:
from scapy.all import *
# load the PCAP file using rdpcap
packets = rdpcap('dhcp.pcap')
# Let's iterate through every packet
for packet in packets:
source_ip = packet.getlayer(IP).src
destination_ip = packet.getlayer(IP).dst
print(f"{source_ip} --> {destination_ip}")
# TODO: replace in model and write to PCAP file using wrpcap
See also
IncognitJoe's tutorial on Reading Pcap files with Scapy.
Getting source IP of packet using Scapy for getting the IP fields of a packet.
Update:
How to replace in your case
Refined talentldk's solution with some simplification and debug-prints:
no separate import needed (all imports all)
no writer needed, just use wrpcap to write the read model
use a replacement-dict with string's replace function where dict entry (a tuple) is passed to function using the unpack-operator * as prefix resulting in 2 separate arguments (key is replaced by value)
use iter over the dict's items to process all replacements (here 2 entries) where the next item can be drawn by next function
from scapy.all import *
# rdpcap loads in our pcap file
packets = rdpcap('dhcp.pcap')
# define search
first_src_ip = packets[0][IP].src
first_dst_ip = packets[0][IP].dst
# define new ip address to use as replacement
ip_replacement = {f"{first_src_ip}" : '8.8.8.8', f"{first_dst_ip}" : '1.1.1.1'}
print(f"replacement: {ip_replacement}")
# Let's iterate through every packet
for i, packet in enumerate(packets):
source_ip = packet.getlayer(IP).src
destination_ip = packet.getlayer(IP).dst
print(f"[{i:3}] original: {source_ip} --> {destination_ip}")
# replace in model
replacement = iter(ip_replacement.items())
source_ip = source_ip.replace(*next(replacement))
destination_ip = destination_ip.replace(*next(replacement))
print(f"[{i:3}] replaced: {source_ip} --> {destination_ip}")
wrpcap("dhcp_replaced.pcap", packets)
Prints:
replacement: {'0.0.0.0': '8.8.8.8', '255.255.255.255': '1.1.1.1'}
[ 0] original: 0.0.0.0 --> 255.255.255.255
[ 0] replaced: 8.8.8.8 --> 1.1.1.1
[ 1] original: 192.168.0.1 --> 192.168.0.10
[ 1] replaced: 192.168.0.1 --> 192.168.0.10
[ 2] original: 0.0.0.0 --> 255.255.255.255
[ 2] replaced: 8.8.8.8 --> 1.1.1.1
[ 3] original: 192.168.0.1 --> 192.168.0.10
[ 3] replaced: 192.168.0.1 --> 192.168.0.10
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)
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've searched all over the web for the answer to my question and I've used aspects of what I've learned to help me get to this point. However, I've been unable to find the solution to get me where I need to be.
In the shortest way possible, I need to create a dictionary containing a dictionary and a list of values as read in from a file, and print the output.
I was able to do this using a statically created dictionary, but I seem to be unable to create the dictionary in the same format while reading in from a file.
Here is the code I was able to get working:
routers = {'fre-agg1': {'interface Te0/1/0/0': ["rate-limit input 135", "rate-limit input 136"],
'interface Te0/2/0/0': ["rate-limit input 135", "rate-limit input 136"]},
'fre-agg2': {'interface Te0/3/0/0': ["rate-limit input 135", "rate-limit input 136", "rate-limit input 137"]}}
for rname in routers:
print rname
for iname in routers[rname]:
print iname
for int_config in routers[rname][iname]:
print int_config
The output of this prints exactly in the format I need it to be:
fre-agg2
interface Te0/3/0/0
rate-limit input 135
rate-limit input 136
rate-limit input 137
fre-agg1
interface Te0/1/0/0
rate-limit input 135
rate-limit input 136
interface Te0/2/0/0
rate-limit input 135
rate-limit input 136
The file I am trying to read in is in a different format:
ama-coe:interface Loopback0
ama-coe: ip address 10.1.1.1 255.255.255.255
ama-coe:interface GigabitEthernet0/0/0
ama-coe: description EGM to xyz Gi2/0/1
ama-coe: ip address 10.2.1.1 255.255.255.254
ama-coe:interface GigabitEthernet0/0/1
ama-coe: description EGM to abc Gi0/0/1
ama-coe: ip address 10.3.1.1 255.255.255.254
For this file, I'd like the output of the file as the same output shown above, with the interface configuration listed under the interface name, listed under the device name
ama-coe
interface Loopback0
ip address 10.1.1.1 255.255.255.255
interface GigabitEthernet0/0/0
etc etc etc
So far, here is the code I have:
routers = {}
with open('cpe-interfaces-ipaddress.txt') as inputFile:
inputData = inputFile.read().splitlines()
for rname in inputData:
device, stuff = rname.split(':')
if not device in routers:
routers[device] = None
elif stuff == "interface":
routers[device][None] = stuff
I know this code is extremely incomplete but I can't for the life of me figure out the dictionary and list structure as I did when statically creating the dict.
Any help that can be provided would be greatly appreciated.
Thank you.
routers = {}
with open('cpe-interfaces-ipaddress.txt') as inputFile:
cur_interface = None
for rname in inputFile:
device, stuff = rname.strip().split(':')
print device, stuff, cur_interface
if not device in routers:
routers[device] = {}
if stuff.startswith("interface"):
key_word, interface = stuff.split(' ')
routers[device].setdefault(interface, [])
cur_interface = interface
else: # ip address
routers[device][cur_interface].append(stuff)
Not knowing if this meet your need. I made an assumption that each ip address is belong to previous interface.
The way using a dictionary to organize stuff is common. You should learn some built-in methods, such as setdefault and append.