Python JSON try except block not working - python

After multiple attempts, this code still fails. What I am trying to do is send "cpu stats" as JSON over to the server. The thing is, cpustats alone is fine - there is just 1 namedtuple with the different cpupercentages - user, idle, etc.. But 'percpu' returns a list of each cpu's namedtuple (of user, idle, etc.). So I cannot convert the list to a dictionary. I am trying to loop through the list and then send each one of the namedtuple to the server. (For ref. - I am using 2.7.5). The script worked fine without the attempt to loop and try/except - it returned a '200 OK'. But now when I run it it doesn't even return an error, any response message/status. It's as if the script is just bypassing the whole try/except block. Just the 'print cpuStats' line at the end delivers as it should. (The indentation in this question is a bit off but it's fine in the script)
import psutil
import socket
import time
import sample
import json
import httplib
import urllib
serverHost = sample.host
port = sample.port
thisClient = socket.gethostname()
currentTime = int(time.time())
s = socket.socket()
s.connect((serverHost,port))
cpuStats = psutil.cpu_times_percent(percpu=True)
print cpuStats
def loop_thru_cpus():
for i in cpuStats:
cpuStats = cpuStats[i]
cpuStats = json.dumps(cpuStats._asdict())
try:
command = 'put cpu.usr ' + str(currentTime) + " " + str(cpuStats[0]) + "host ="+ thisClient+ "/n"
s.sendall(command)
command = 'put cpu.nice ' + str(currentTime) + " " + str(cpuStats[1]) + "host ="+ thisClient+ "/n"
s.sendall(command)
command = 'put cpu.sys ' + str(currentTime) + " " + str(cpuStats[2]) + "host ="+ thisClient+ "/n"
s.sendall(command)
command = 'put cpu.idle ' + str(currentTime) + " " + str(cpuStats[3]) + "host ="+ thisClient+ "/n"
s.sendall(command)
params = urllib.urlencode({'cpuStats': cpuStats, 'thisClient': 1234})
headers = httplib.HTTPConnection(serverHost, port)
conn.request("POST", "", params, headers)
response = conn.response()
print response.status, response.reason
except IndexError:
break
i = i+1
s.close()

Instead of:
def loop_thru_cpus():
for i in cpuStats:
cpuStats = cpuStats[i]
cpuStats = json.dumps(cpuStats._asdict())
...
i = i+1
Try:
def loop_thru_cpus():
for stat in cpuStats:
stat = json.dumps(stat._asdict())
When you say
for i in cpuStats:
i takes on values from cpuStats. i is not an integer in this case. So i = i+1 makes no sense.
cpuStats = cpuStats[i]
This probably raised an IndexError (since i is not an integer), but for some reason you are not seeing the exception that was raised.
Also note that you are redefining cpuStats here, which is probably not what you want to do.
You probably do have indentation errors in your code. Running the code you posted through cat -A shows tabs (indicated below by ^I):
try:$
^I $
command = 'put cpu.usr ' + str(currentTime) + " " + str(cpuStats[0]) + "host ="+ thisClient+ "/n"$
...
params = urllib.urlencode({'cpuStats': cpuStats, 'thisClient': 1234})$
...
^I print response.status, response.reason$
$
^I except IndexError:$
break$
You can not mix tabs and spaces an indentation in Python code. Either use one or the other. The PEP8 style guide (and most code you see on the net) uses 4 spaces. Mixing tabs and spaces usually results in an IndentationError, but sometimes you don't get an error and just code that behaves in unexpected ways. So (if using the 4-spaces convention) be careful to use an editor that adds 4 spaces when the tab key is pressed.
Since you are not seeing the IndexError, you may not be seeing the IndentationError that should have been occurred either. How exactly are you running the problem?

Related

Remove Duplicate IP Addresses with Scapy

I have a script to listen for incoming traffic and print out only the string “IP 1.1.1.1 53" when a packet hits the line. But now that I’m doing IP resolve on the IPs, I need to access the “ip_src” variable and only do the geolocation once on each ip, rather than resolve the same IP over and over as they come in. My current code is:
#!/usr/bin/python3
from scapy.all import *
import ipinfo
def print_summary(pkt):
if IP in pkt:
ip_src=pkt[IP].src
if UDP in pkt:
udp_sport=pkt[UDP].sport
access_token = ''
handler = ipinfo.getHandler(access_token)
match = handler.getDetails(ip_src)
c = match.details.get('city')
s = match.details.get('region')
strang = ("IP " + str(ip_src) + " " + str(udp_sport) + " " + str(c) + ", " + str(s))
print(strang)
sniff(filter="",prn=print_summary)
As you can see the “print_summary” function is called by “prn” which is called for each pkt. I basically want to mimic the functionality of uniq and sort, since they can successfully filter out duplicates from a file, but I’d like to have it all in one script.
EDIT - Trying Set():
So using the code:
from scapy.all import *
def print_summary(pkt):
if IP in pkt:
ip_src=pkt[IP].src
if UDP in pkt:
udp_sport=pkt[UDP].sport
lines_set = set(ip_src)
strang = ("IP " + str(ip_src) + " " + str(udp_sport))
if ip_src not in lines_set:
for line in lines_set:
print(line)
sniff(filter="",prn=print_summary)
I get the output: (in the terminal each character has a trailing newline)
2 . 3 5 8 0 1 2 . 4 8 0 1 . 6
This adds a set variable to keep track of which addresses you have already seen.
#!/usr/bin/python3
from scapy.all import *
import ipinfo
seen = set()
def print_summary(pkt):
if IP in pkt:
ip_src=pkt[IP].src
if UDP in pkt and ip_src not in seen:
seen.add(ip_src)
udp_sport=pkt[UDP].sport
access_token = ''
handler = ipinfo.getHandler(access_token)
match = handler.getDetails(ip_src)
c = match.details.get('city')
s = match.details.get('region')
strang = ("IP " + str(ip_src) + " " + str(udp_sport) + " " + str(c) + ", " + str(s))
print(strang)
sniff(filter="ip",prn=print_summary)
I also changed the indentation of the second if to avoid getting a traceback if somehow you would receive a packet which doesn't have the IP member; though I also updated the filter expression to hopefully prevent that from ever happening in the first place.

Python Netmiko OSError: Search pattern never detected in send_command_expect:

I recently started programming with Python. I work as a network engineer and am currently building a program to pull "state dumps" from Ciena devices. I use netmiko to connect to the device.
Now I always get the following error:
OSError: Search pattern never detected in send_command_expect: 5160_1>
"5160_1>" is the hostname / prompt on the switch. I have read that I can give "expect_string" to a "send_command". Unfortunately, this has no effect and I still get this error.
This is the function with which I create the state dump and call the function for the file download.
def create_sd():
for ip in sw_connect_ips:
try:
sw_connection = ConnectHandler(device_type=sw_dev_type, host=ip, username=sw_usr, password=sw_pw)
try:
print('\nconnnected to host > ' + ip + '\n')
hostname = sw_connection.find_prompt()
print('hostname of device > ' + hostname)
sw_connection.send_command('system server sftp enable', expect_string=hostname)
sw_connection.send_command('configuration save', expect_string=hostname)
sw_output = sw_connection.send_command('system state-dump file-name ' + ip + '_sd_timestamp_' + str(date.hour) + '_' + str(date.minute) + '_' + str(date.second), expect_string=hostname + ' ')
filename = ip + '_sd_timestamp_' + str(date.hour) + '_' + str(date.minute) + '_' + str(date.second)
print('got state-dump ' + filename + ' from host > ' + ip)
logging.debug(sw_output)
logging.debug(sw_connection)
sw_connection.disconnect()
try:
sftp_get(filename, ip)
except:
raise Exception('scp failed')
except:
raise Exception('command does not exist on switch > ' + ip)
except:
raise SSHException('unable to connect to switch check username, password and ip address')
I don't know whether all exceptions make so much sense. Maybe someone has a tip for me.
Thanks in advance.
Edit: What is strange in my opinion is that it only occurs with some switches.
in the command with which the state dump is created, I have increased the "send_command" delay factor to 5.
sw_output = sw_connection.send_command ('system state-dump file-name' + ip + '_sd_timestamp_' + str (date.hour) + '_' + str (date.minute) + '_' + str (date.second) , expect_string = hostname, delay_factor = 5)
As a result, I no longer get a netmiko exception and the program runs without problems.

Sending second TCP message doesn't get recognized/no reaction on serverside, with netcat works fine

This is a task for CTF preparation which can be found on https://rookies.fluxfingers.net/code.php?p=chal&id=142 .
The task is to calculate the sum of all even numbers - the sum of all uneven numbers.
I solved this but when sending the answer message to the server it doesn't respond with the flag.
But with nc rkchals.fluxfingers.net 5002 a second message can be send.
My code:
import socket
import re
#connection establishing
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("rkchals.fluxfingers.net",5002))
message = str(s.recv(3000))
#data processing
numbers= re.findall("\d+",message)
uneven_numbers=list()
even_numbers = list()
for i in numbers:
if(int(i)%2==0):
even_numbers.append(int(i))
else:
uneven_numbers.append(int(i))
answer = sum(even_numbers)-sum(uneven_numbers)
#log
print("server says: " + message + "\n")
print("numberarray is: " + str(numbers) + "\n")
print("even numbers are: " + str(even_numbers) + "\n")
print("odd numbers are: " + str(uneven_numbers) + "\n")
print("sum of even - sum of odd: " + str(answer) + "\n")
#sending the answer as string to get the flag
s.sendall(bytes(str(answer),"utf-8"))
print("flag is: " + str(s.recv(1024)))
At the end when I send the answer the server ignores it(?), because the last command should give me the flag as an answer in result of sending the answer previously.
What should I change so that the server can receive my second message?
I tried:
timeout(?)
I lack of knowledge and I couldn't find an answer here.
Because the server application expects an Enter, I simply added this to my code:
s.sendall(bytes(str(answer) + "\n","utf-8"))
Then ther server responds normally with the flag.

Using Python 3.4 to Ping a network then report address, dns name, etc.

I wanted to create a Python program that does several things. Ping all addresses in a predefined network, gather the DNS information, write a file with IP address, DNS name, ping fail or pass, date. Then run and email the resulting file to myself once a week, every Friday. I have created this program and will post my own answer. I am new to Python and was able to get this written with the help from other answers posted on this site. Thanks to all those who contributed answers on this site. Hope the answer I post will help someone else.
#!/usr/bin/python3.4
#Above statement makes sure you are using version 3.4
#when multiple versions are installed. has to be the 1st line.
# Import modules
import subprocess
import socket
import errno
import time
import datetime
import ipaddress
today = datetime.date.today()
# define DNS lookup and error handling
# return none,none,none needed otherwise if no DNS record
# the routine errors out and the program stops
def lookup(addr):
try:
return socket.gethostbyaddr(addr)
except socket.herror:
return None, None, None
# Prompt the user to input a network address
# commented out the prompt for input so it can run unattended
# net_addr = input("Enter a network address in CIDR
format(ex.192.168.1.0/24): ")
net_addr = ('192.168.1.0/24')
# Create the network
ip_net = ipaddress.ip_network(net_addr)
# Get all hosts on that network
all_hosts = list(ip_net.hosts())
# Configure subprocess to hide the console window
# removed code due to errors not windows linux
# setup online and offline count variables
offCnt = 0
onCnt = 0
# Open file and or create if it doesn't exist.
# file to be overwritten each time the program is run.
file = open("lab-ip.doc","w")
# For each IP address in the subnet,
# run the ping command with subprocess.popen interface
# Grab the DNS information for each IP address
# Print to console add counters and write to file.
for i in range(len(all_hosts)):
output = subprocess.Popen(['ping', '-c', '2', str(all_hosts[i])],
stdout=subprocess.PIPE).communicate()[0]
name,alias,addresslist = lookup(str(all_hosts[i]))
if "Destination Host Unreachable" in output.decode('utf-8'):
print(str(all_hosts[i]), " Ping Fail", str(name), today)
file.write(str(all_hosts[i]) + " Ping Fail - " + str(name) + " " + str(today) + "\n")
offCnt = offCnt + 1
elif "Request timed out" in output.decode('utf-8'):
print(str(all_hosts[i]), " Ping Fail", str(name), today)
file.write(str(all_hosts[i]) + " Ping Fail - " + str(name) + " " + str(today) + "\n")
offCnt = offCnt + 1
else:
print(str(all_hosts[i]), " Ping Pass", str(name), today)
file.write(str(all_hosts[i]) + " Ping Pass - " + str(name) + " " + str(today) + "\n")
onCnt = onCnt + 1
print ("Pass count = ", str(onCnt))
file.write("Pass count = " + str(onCnt))
print ("Fail count = ", str(offCnt))
file.write(" Fail count = " + str(offCnt))
file.close()
# Import yagmail for the actual sending function
import yagmail
yag = yagmail.SMTP('Gmail-id', 'gmail-pswd')
yag.send('email#email.com', subject = "Lab-ip List",contents = 'lab-ip.doc')
yag.send('email2#email2.com', subject = "Lab-ip List",contents = 'lab-ip.doc')
#end

HTTP Post request with Python JSON

I am trying to send data to a URL. I've a code to send it for each cpu on my Mac. But the current code loops through each of the cpustats and sends them 1 after the other. I need to send all of them in 1 POST 'cycle' but it should be formatted such that it sends it like this -
cpuStats = {nice: 123.0, idle:123.0....}
cpuStats = {nice: 123.0, idle:123.0....}
cpuStats = {nice: 123.0, idle:123.0....}
and so on...
Further, the current code pulls the stats from my Mac (with a '200 OK' for each cpustat) but when I run it on Linux, Windows, it just returns the prompt without giving any errors or stats. My guess is that it has to do with the 'break' at 'socket.error:' (My Mac has 4 cpus but the Linux and Windows machines on which I test it have 1 each.
import psutil
import socket
import time
import sample
import json
import httplib
import urllib
serverHost = sample.host
port = sample.port
thisClient = socket.gethostname()
currentTime = int(time.time())
s = socket.socket()
s.connect((serverHost,port))
cpuStats = psutil.cpu_times_percent(percpu=True)
def loop_thru_cpus():
global cpuStats
for stat in cpuStats:
stat = json.dumps(stat._asdict())
try:
command = 'put cpu.usr ' + str(currentTime) + " " + str(cpuStats[0]) + "host ="+ thisClient+ "/n"
s.sendall(command)
command = 'put cpu.nice ' + str(currentTime) + " " + str(cpuStats[1]) + "host ="+ thisClient+ "/n"
s.sendall(command)
command = 'put cpu.sys ' + str(currentTime) + " " + str(cpuStats[2]) + "host ="+ thisClient+ "/n"
s.sendall(command)
command = 'put cpu.idle ' + str(currentTime) + " " + str(cpuStats[3]) + "host ="+ thisClient+ "/n"
s.sendall(command)
params = urllib.urlencode({'cpuStats': stat, 'thisClient': 1234})
headers = headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
conn = httplib.HTTPConnection(serverHost, port)
conn.request("POST", "", params, headers)
response = conn.getresponse()
print response.status, response.reason
except IndexError:
continue
except socket.error:
print "Connection refused"
continue
print stat
loop_thru_cpus()
s.close()
If you're just trying to send the data all at once you should realize that you're not actually sending a dictionary across, but instead you're sending a string. In that case, you could easily send all the data in one go by just constructing your data like so:
data = "\n".join([json.dumps(stat._asdict()) for stat in cpuStats])
If that endpoint is someone else's that might not be sensible, but assuming that's your own endpoint you're pointing at it should be pretty trivial to unbundle this data.
Additionally I would HIGHLY suggest switching to the requests module over urllib as it extends all of the same functionality in a MUCH easier wrapper. For instance, in requests you would send that request by doing the following:
import requests
response = requests.post("your://url.here", data=data)
print response.content

Categories

Resources