config from router shows as one line need multiline for ciscoconfparse - python-3.x

Network guy that's new to Python and programming and found this ciscoconfparse library that looks to have some pretty useful features. I'm running into an issue that I'm sure is something basic, but haven't figured it out. I'm trying to pull snmp config from a router to create a config set to remove v2 configs. Using netmiko to grab output of "show run | in snmp" then parse it. The config that comes back shows as one line. When using ciscoconfparse statements to delete some lines, it deletes everything (assuming because it is only one line) so I have nothing left to build.
in all examples online, sample config looks like this and the functions work as it is multiple lines.
conf=[
'access-list dmz_inbound extended deny udp object training-network any4 eq snmp',
'snmp-server host inside 10.10.10.10 poll community ***** version 2c',
'snmp-server host inside 10.20.20.20 poll community ***** version 2c',
'no snmp-server location',
'no snmp-server contact',
'snmp-server community *****',
'!'
]
when I actually pull config from a router, it looks like this with newline characters but gets parsed as 1 line:
'access-list testNada extended permit udp host 10.10.10.10 eq snmp host 10.20.10.10 eq snmp \nsnmp-server host inside 10.11.11.11 community ***** version 2c\nsnmp-server host inside 10.5.5.5 poll community ***** version 2c\nno snmp-server location\nno snmp-server contact\nsnmp-server community *****\n']
snippet of code I'm running. the delete line statements delete the whole config snip rather than just the line matching the arg.
conf = [ssh.send_command("show run | include snmp")]
parse = CiscoConfParse(conf)
parse.delete_lines('no snmp-server')
parse.delete_lines('access-list')
newConf = (parse.replace_lines('snmp', 'no snmp',excludespec='v3'))
ssh.send_config_set(newConf)
how do I get the config pulled directly from the router to show as multi-line so I can use the ciscoconfparse functions?

You are passing a string to CiscoConfParse instead of a list.
Try the below:
conf = [ssh.send_command("show run | include snmp")]
# this will change your string into a list
formatted_output = conf.splitlines()
parse = CiscoConfParse(formatted_output)
parse.delete_lines('no snmp-server')
parse.delete_lines('access-list')
newConf = (parse.replace_lines('snmp', 'no snmp',excludespec='v3'))
Explanation: Netmiko will return a string (/n means a new line, but it's still a string). When you use splitlines - it will transfer your string into a list (each line will be a new element)

was able to get it to work by iterating over the list returned by netmiko, which returned a 'list in a list'. basically it was a list that had one index that happened to be the list containing the config.
newConf=[]
for i in conf:
newConf.append(i.split("\n"))
which returned
[['access-list testNada extended permit udp host 10.10.3.10 eq snmp host 10.10.10.10 eq snmp ', 'snmp-server host inside 10.4.233.8 community ***** version 2c', ....]]
then ran it through the parser for index 0.
parse = CiscoConfParse(newConf[0])
which resulted in multiple lines and I could use the delete_lines and replace_lines functions to produce the negated config I want to send back to my devices:
['no snmp-server host inside 10.4.233.8 community ***** version 2c', 'no snmp-server host inside 10.3.25.17 poll community ***** version 2c',...]]

Related

Python3 pass variable to paramiko

So i'm taking all ips from the range 1.1.1.0 to 1.1.1.10 and individually connecting to ssh with each ip. When I run "print(host1)" it gives me the ip but when I use the variable host1 in ssh.connect I get the error "getaddrinfo() argument 1 must be string or None" and if I put the variable host1 into quotes I get the error "can only concatenate str (not "IPv4Address") to str"
start_ip = ipaddress.IPv4Address('1.1.1.0')
end_ip = ipaddress.IPv4Address('1.1.1.10')
for ip_int in range(int(start_ip), int(end_ip)):
host1 = ipaddress.IPv4Address(ip_int)
print(ipaddress.IPv4Address(ip_int))
print(host1)
def ssh_connect(password, code=0):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect(host1, port=22, username=username, password=password, timeout=5)
Python is tab dependent. So you had to be careful about that when you code out your control structures. The indentation tells Python which statements should be included in your loops. My advice is to remove the function definition until you get this piece of code working and then if you wanted to generalize the functionality later when you know Python better, better to have a piece of code that works than a piece of code that you don't quite grasp. But spacing at the beginning of the line is used to indicate the scope of control structures. I never saw that before I started coding with Python and it was the hardest thing for me to grasp. It looks like you might be having trouble with that too.
If you look for the subheading 'Using IP Addresses with other modules' you'll see that you had to typecast the hostname returned by IPv4Address as a string by using str(...)
https://docs.python.org/3/howto/ipaddress.html

How can you ensure a viable endpoint for a stanza CoreNLPClient?

I would like to use the stanza CoreNLPClient to extract noun phrases, similar to this method.
However, I cannot seem to find a good port to start the server on. The default is 9000, but this is often occupied, as indicated by the error message:
PermanentlyFailedException: Error: unable to start the CoreNLP server
on port 9000 (possibly something is already running there)
EDIT: Port 9000 is in use by python.exe, which is why I can't just shut the process down to make space for the CoreNLPClient.
Then, when I select other ports such as 7999, 8000, or 8080, the server keeps listening indefinetely, not executing the consecutive code lines, showing only the following:
2021-07-19 12:05:55 INFO: Starting server with command: java -Xmx8G -cp C:\Users\timjo\stanza_corenlp* edu.stanford.nlp.pipeline.StanfordCoreNLPServer -port 7998 -timeout 60000 -threads 5 -maxCharLength 100000 -quiet True -serverProperties corenlp_server-2e15724b8064491b.props -preload -outputFormat serialized
I have the latest version of stanza installed, and am running the following code from an .ipynb file in VS Code:
# sample sentence
sentence = "Albert Einstein was a German-born theoretical physicist."
# start the client as indicated in the docs
with CoreNLPClient(properties='corenlp_server-2e15724b8064491b.props', endpoint='https://localhost:7998', memory='8G', be_quiet=True) as client:
matches = client.tregex(text=sentence, pattern = 'NP')
# extract the noun phrases and their indices
noun_phrases = [[text, begin, end] for text, begin, end in
zip([sentence[match_id]['spanString'] for sentence in matches['sentences'] for match_id in sentence],
[sentence[match_id]['characterOffsetBegin'] for sentence in matches['sentences'] for match_id in sentence],
[sentence[match_id]['characterOffsetEnd'] for sentence in matches['sentences'] for match_id in sentence])]
Main question: How can I ensure that the server starts on an open port, and closes afterwards? I would prefer having a semi-automatic way to finding open / shutting down occupied ports for the client to run on.
In general it is sufficient to choose another number that nothing else is using – maybe 9017? There are lots of numbers to choose from! But the more careful choice would be to create the CoreNLPClient in a while loop with a try/catch and to increment the port number till you found one that was open.
After 2 hours of working on this, I now know the following:
Taking port 9000 is not an option, given that it is used by python. Informal evidence points towards this having to do something with using a jupyter notebook as opposed to a 'regular' python .py file.
Regarding the Client not closing when using other endpoints: I should've simply used http://localhost:port' instead of https://....
Hopefully this can help someone else struggling with this problem. I guess this was my non-computer science background seeping through.
(edited to resolve typos)

AWS changes the port number to name

AWS automatically changes the well known port numbers to name.
For example 554 to rtsp.
When I am installing iptable rules, with the port number as 554, its getting changed to rtsp. This is creating problem when searching because my program passes 554 as parameter.
How to make sure that the AWS doesn't change the number to name ?
In the picture we can see the dpt:rtsp, which actually should be dpt:554.
Perhaps you're looking for iptables --list -n? The -n prints "numeric output of addresses and ports."

Write to rsyslog with custom app name

What I have
I have written a Python class that writes messages to a custom log via rsyslog. This is scaling off of my previous question, which I have temporarily circumvented by prepending my app's name to each message and have rsyslog configured to put all logs containing my app's name to my custom log. However, I am concerned that something else on the system writes to rsyslog and that message just so happens to contain my app's name, rsyslog will detect this send that log entry to my log. I would also prefer the look of my app's name instead of journal appearing throughout my log.
Attached is my code:
import logging
from logging import handlers
lumberjack = logging.getLogger("MyAppName")
lumberjack.setLevel(logging.INFO)
handler = handlers.SysLogHandler(address='/dev/log')
handler.setFormatter(logging.Formatter('%(name)s %(levelname)s: %(message)s'))
handler.ident = "MyAppName"
lumberjack.addHandler(handler)
lumberjack.critical("I'm okay")
Goal
The following two messages are examples. The first was written by my Python class. The second was written by me running logger -t MyAppName -s "Hey buddy, I think you’ve got the wrong app name"
Aug 22 15:49:53 melchior journal: MyAppNameMyAppName CRITICAL: I'm okay.
Aug 22 15:57:06 melchior MyAppName: Hey buddy, I think you’ve got the wrong app name
Question
What do I have to change in my Python code to get these lines to look the same, but with the levelname included as I have already done so?
Change the following line
handler.setFormatter(logging.Formatter('%(name)s %(levelname)s: %(message)s'))
to look like this (basically just add a colon after %(name)s:
handler.setFormatter(logging.Formatter('%(name)s: %(levelname)s: %(message)s'))
then remove the following line to avoid app name duplication:
handler.ident = "MyAppName"
and now it does the trick:
Sep 10 06:52:33 hostname MyAppName: CRITICAL: I'm okay

Bro network monitor - cannot open file; headers are incorrect

I have searched high and low for an answer to this, but I have been stuck for 2 days. I am attempting to read data into BRO IDS from a file using :
Input::add_table([$source=sinkhole_list_location,
$name="sinkhole", $idx=Idx, $val=Val, $destination=sinkhole_list2, $mode=Input::REREAD]);
The file is formatted as stated by Bro documentation:
fields ip ipname
10.10.20.20 hi
8.8.8.8 hey
192.168.1.1 yo
Yet whenever I run this, or any of the other scripts out there on my Bro IDS I always get HEADERS ARE INCORRECT. What format should the file be in??????
error: sinkhole_ip.dat/Input::READER_ASCII: Did not find requested field ip in input data file sinkhole_ip.dat.
1481713377.164791 error: sinkhole_ip.dat/Input::READER_ASCII: Init: cannot open sinkhole_ip.dat; headers are incorrect
I can answer my own question here, its in the use of tab seperated files which BRO uses by default. Every single field must be tabbed.
Then you can output the table contents as a test within... Input::end_of_data event() as once this event has been received all data from the input file is available in the table.

Resources