Parse XML input from UDP port - python

I'm a newbie in python, just done only a couple of scripts.
Now I need to listen and process a xml text that is being received from a udp socket.
By the moment I have the first part but i don't know how to proceed.
import socket
import lxml.etree
port = 7059
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("", port))
print "waiting on port:", port
while 1:
data, addr = s.recvfrom(1024)
print data
I'm receiving the data ok, and it's printed on the screen:
<electricity id='4437190066CD'><timestamp>1532728995</timestamp><signal rssi='-78' lqi='94'/><battery level='10%'/><chan id='0'><curr units='w'>609.00</curr><day units='wh'>34.64</day></chan><chan id='1'><curr units='w'>42.00</curr><day units='wh'>2.38</day></chan><chan id='2'><curr units='w'>538.00</curr><day units='wh'>30.43</day></chan></electricity>
But I need to get or parse de values in bold:
<chan id='0'><curr units='w'>609.00</curr>
<chan id='1'><curr units='w'>42.00</curr>
<chan id='2'><curr units='w'>538.00</curr>
and asign to something like a var with it's sub objects:
power.ch0 = 609.00
power.ch1 = 42.00
power.ch2 = 538.00
with that variable, then I will do a request to my porwer monitoring system api to send these values.
I usually use bash for scripting, and I'm pretty happy with it, but I think that this time not rich enough and python seems to be my solution
Thanks in advance for your help!!

There are several ways to do this. First, I do not see where you are using the xml.etree module. Take a look at the docs real fast: https://docs.python.org/3/library/xml.etree.elementtree.html
Also, you can achieve this with BeautifulSoup as well: https://www.crummy.com/software/BeautifulSoup/bs4/doc/
Lastly, you can achieve this with the .replace() and .strip() functions as well

Related

sending data with a python socket isnt the same as netcat - buffer overflow

I am trying to practice buffer overflow using dostackbufferoverflowgood.exe and I encountered a problem.
While using netcat to send 5000 A's by using the command echo `python3 -c "print('A'*146 + 'BBBB')"` | nc 192.168.1.237 31337 the program is crashing and the value of EIP is 42424242, so that's good.
When trying to do the same thing with a python script, nothing is happening, and I tried debugging it for a while including using python2, wiresharking but all seems the same both on client and the server, except that the server isn't replying, which is weird but it is replying to nc, so it must be something with the python script.
python script:
import socket
server = '192.168.1.237'
port = 31337
data = b'A'*146 + b'B'*4
print(len(data))
print(data)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
print(f'trying to connect to {server}')
s.connect((server,port))
s.send(data)
print('data was sent')
data = s.recv(1024)
print(data)
Again, when capturing wireshark everything seems to be the same, so I have no idea why this is happening.
If someone encountered anything like that, would appreciate any help, thank you!
I think you should put '\n\r' at the end of data.
The code should be like:
s.send(data +'\n\r')

Having problems with reading data from the serial port

Having issues reading data from a serial connection. I connect and send write instructions to the device connected to the serial port but when I get a response back it is not in the form it should be taking. What I expect should look something like "^S015NOM120,60,,,600" but it looks like "8". I need to be able to read the correct message, and if you know how to continuously read look for messages I would be much appreciated.
I have tried serial.readlines(), serail.readline(), io.readlines(), and io.readline(). These keep giving me back error to their arguments.
def testcommand():
ser = serial.Serial('COM7',9600)
command = b'^P003NOM'
ser.write(command)
testread =ser.read(55)
print(testread)
Found the answer. In the serial.serial python will not read unless it know how long it should listen for. It now provides me with an answer I was expecting. I also switched read to readline().
serial.Serial('COM7',9600, timeout = 1)
testread = readline()

Python based network sniffer (scapy not good enough?)

I am looking for the specific task:
Grab the payload/data from a packet -> Append to a file... BUT. I want specifically to follow packets according to flags/ICMP types/etc... So lets say I want specifically to take the payload of "echo" packets and not the rest.
My (ineffective) code is the following:
from scapy.all import *
f= open('filecaptured', 'a+')
def pkt_diam(pkt):
raw = pkt.getlayer(Raw).load
print raw
# pkt.show()
# fo = open("payload", "wb")
f.write(raw);
sniff (filter="icmp" , store=0, prn=pkt_diam, timeout = 120 )
The problem here is that I cannot find a way to sniff specifically for "type = echo request" and the only parameters that I can use is 'protocol' and host or 'and not host 127.0.0.1'.
Is there a way around this?
I think for this one I need to use ctypes and libpcap.so but I am not sure... (I didnt find any [other] libraries for python - sniffing )
I don't have scapy installed right now, but what if you simply check for the type echo-reply in your callback-function pkt_diam:
if not "echo-reply" in pkt.show():
return
Try filter="icmp[0]=8" for filtering during capture or
if pkt[ICMP].type==8:
in callback function.

Build/Parse an XML document from a socketstream in Python

I have an issue parsing a continuous stream of (multiple) xml documents sent by a third party over a socket. A sample of the xml stream sent over the socket is:
<?xml version="1.0"?><event><user id="1098"/><viewpage>109958</viewpage></event>
<?xml version="1.0"?><event><user id="1482"/><actions><edit>102865</edit><commit>1592356</commit></actions></event>
etc.
Here's the code I'm using:
import socket
import xml.etree.cElementTree as etree
from StringIO import StringIO
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "IP.IP.IP.IP"
port = "8080"
addr = (host,port)
s.connect(addr)
def iparse(packet):
for _, element in etree.iterparse(packet):
print ("%s, %s" %(element.tag, element.text))
element.clear()
#if complete <event> node received, publish node
data = "<feeds>"
while 1:
chunk = s.recv(1024)
#replace the xml doc declarations as comments
data += (chunk.replace("<?","<!--")).replace("?>","-->")
iparse(StringIO(data))
Things work just fine...however, the for loop in iparse iterates through the entire doc each time. Is it possible for iparse to build and iterate through one well-formed tag node (event) as it appears over the stream instead? Note that there is no way in which I can set the chunk size to read a well-formed packet. I could use a buffer, then build the packet and only send to iparse once the packet is well-formed, but that would likely introduce unwanted latency? Is there a better way to handle this?
EDIT:
Each event is distinct but contains arbitrary nodes under the root <event>. iparse is expected to publish the latest event to an arbitrary number of subscribers within a real-time analytics graphing system.
You could have a look at the feed parsing in lxml.etree. However, you're still going to run into problems as your document is continually growing.
Are the XML blobs separated by new line characters? If so I suggest that you buffer until you hit a new line and then send each line to an xml parser. Á la Twisted's LineReceiver.
Actually, if it was me, I'd probably write this application in Twisted. Gluing together network services is a common use case for it for me.

TCP Socket file transfer

I'm trying to write a secure transfer file program using Python and AES and i've got a problem i don't totally understand. I send my file by parsing it with 1024 bytes chunks and sending them over but the server side who receive the data crashes ( I use AES CBC therefore my data length must be a multiple of 16 bytes ) and the error i get says that it is not.
I tried to print the length of the data sent by the client on the client side and the length of the data received on the server and it shows that the client is sending exactly 1024 bytes each time like it's supposed to, but the server side shows that at some point in time, a received packet is not and so less than 1024 bytes ( for example 743 bytes ).
I tried to put a time.sleep(0.5) between each socket send on the client side and it seems to work. Is it possible that it is some kind of socket buffer failure on the server side ? That too much data is being send too fast by the client and that it breaks somehow the socket buffer on the server side so the data is corrupted or vanish and the recv(1024) only receive a broken chunk? That's the only thing i could think of, but this may also be completely false, if anyone has an idea of why this is not working properly it would be great ;)
Following my idea i tried :
self.s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 32768000)
print socket.SO_RCVBUF
I tried to put a 32mbytes buffer on the server side but On Windows XP it shows 4098 on the print and on linux it shows only 8. I don't know how i must interpret this, the only thing i know is that it seems that it doesn't have a 32mbytes buffer so the code doesn't work.
Well it's been a really long post, i hope some of you had the courage to read it all to here ! i'm totally lost there so if anyone has any idea about this please share it :D
Thanks to Faisal my code is here :
Server Side: ( count is my filesize/1024 )
while 1:
txt=self.s.recv(1024)
if txt == " ":
break
txt = self.cipher.decrypt(txt)
if countbis == count:
txt = txt.rstrip()
tfile.write(txt)
countbis+=1
Client side :
while 1:
txt= tfile.read(1024)
if not txt:
self.s.send(" ")
break
txt += ' ' * (-len(txt) % 16)
txt = self.cipher.encrypt(txt)
self.s.send(txt)
Thanks in advance,
Nolhian
Welcome to network programming! You've just fallen into the same mistaken assumption that everyone makes the first time through in assuming that client sends & server recives should be symmetric. Unfortunately, this is not the case. The OS allows reception to occur in arbitrarily sized chunks. It's fairly easy to work around though, just buffer your data until the amount you've read in equals the amount you wish to receive. Something along the lines of this will do the trick:
buff=''
while len(buff) < 1024:
buff += s.recv( 1024 - len(buff) )
TCP is a stream protocol, it doesn't conserve message boundaries, as you have just discovered.
As others have pointed out you're probably processing an incomplete message. You need to either have fixed sized messages or have a delimiter (don't forget to escape your data!) so you know when a complete message has been received.
What TCP can guarantee is that all your data arrives, in the right order, at some point. (Unless something unexpected happens, by which it won't arrive.) But it's very possible that the data you send will still arrive in chunks. Much of it is because of limited send- and receive-buffers. What you should do is to continue doing your recv calls until you have enough data to process it. You might might have to call send multiple times; use its return value to keep track of how much data has been sent/buffered so far.
When you do print socket.SO_RCVBUF, you actually print the symbolic SO_RCVBUF contant (except that Python doesn't really have constants); the one used to tell setsockopt what you want to change. To get the current value, you should instead call getsockopt.
Not related to TCP (as that has been answered already), but appending to a string repeatedly will be rather inefficient if you're expecting to receive a lot. It might be better to append to a list and then turn the list into a string when you finished receiving by using ''.join(list).
For many applications, the complexities of TCP are neatly abstracted by Python's asynchat module.
Here is the nice snippet of code that I wrote some time ago, may be not the best , but it could be good example of big files transfer over the local network. http://setahost.com/sending-files-in-local-network-with-python/
As mentioned above
TCP is a stream protocol
You can try this code, where the data is your original data, you can read it from the file or user input
Sender
import socket as s
sock = s.socket(s.AF_INET, s.SOCK_STREAM)
sock.connect((addr,5000))
sock.sendall(data)
finish = t.time()
Receiver
import socket as s
sock = s.socket(s.AF_INET, s.SOCK_STREAM)
sock.setsockopt(s.SOL_SOCKET, s.SO_REUSEADDR, 1)
sock.bind(("", 5000))
sock.listen(1)
conn, _ = sock.accept()
pack = []
while True:
piece = conn.recv(8192)
if not piece:
break
pack.append(piece.decode())

Categories