Unpacking UDP packets python - python

I am receiving UDP packets over wifi running a simple python script on a PC. The server and the PC are in the same subnet.
The server is sending 15 uint_8 (4 bytes each) every 20 ms or so. The data received seems to be corrupted (non Hex values). Any feedback why this could be happening greatly appreciated.
For example I get something like this,
'\xb3}fC\xb7v\t>\xc8X\xd2=g\x8e1\xbf\xe6D3\xbf\x00\x00\x13\xc3\xc8g\x1b#\xc2\x12\xb2B\x01\x000=\x02\xc0~?\x01\x00\x94<\x00\x00\x00\x00\x00\x00\x00\x00\x00
#\x9c\xbe\xac\xc9V#', ('192.168.4.1', 4097))
The script is attached here.
from socket import *
import time
HOST = '192.168.4.10'
PORT = 9048
address = (HOST, PORT)
client_socket = socket(AF_INET, SOCK_DGRAM) #Set Up the Socket
client_socket.bind((HOST, PORT))
client_socket.settimeout(5) #only wait 5 second for a response, otherwise timeout
while(1): #Main Loop
single_var = client_socket.recvfrom(1024)
print single_var #Print the response from Arduino
time.sleep(10/1000000) # sleep 10 microseconds

The print statement doesn't know that you want hex output, so it interprets hex values that have valid character representations as characters. If you want to print it as hex bytes, see the solution in Print a string as hex bytes.
i.e. do:
print ":".join("{:02x}".format(ord(c)) for c in single_var)

Related

About the issue that the character string is broken in TCP/IP communication between different machines

I tried TCP/IP communication between the same machine and TCP/IP communication between different machines.
First of all, I tried communication in the same Windows machine.The server and client code used is:
TCP_server.py
import socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('', 50001))
s.listen(1)
while True:
conn, addr = s.accept()
with conn:
while True:
data = conn.recv(30000)
if not data:
break
if len(data.decode('utf-8')) < 35:
print("error")
break
print(data.decode('utf-8')+"\n")
TCP_client.py
# -*- coding : UTF-8 -*-
import socket
target_ip = "192.168.1.5"
target_port = 50001
buffer_size = 4096
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_client.connect((target_ip,target_port))
message = b'123456789101112131415161718192021222324252627282930\n'
while True:
tcp_client.send(message)
The IP address of my Windows machine is 192.168.1.5, so the above code works. And it executed successfully without any error. The printed string is shown in the image below.
But when I tried to communicate with Mac and Windows using the exact same code, I had a problem. I used a Mac for the client and Windows for the server.The character string output on the server side is as follows.
As you can see from the image above, it is normally printed normally, but sometimes a line break is made and the character string is divided.
And my server-side code says that if the number of characters is less than 35, it will print error. However, error is not printed in this execution result.In other words, communication is not performed twice, but line breaks are inserted in one communication.
Is it possible to avoid this problem? Do I always have to be aware of line breaks when sending from another machine over TCP/IP?
I'm only using Python in this sample, but I had a similar problem using iOS's Swift for client-side code. So I would like to know a general solution.
There is no line break added by transmission of the data. This line break is instead added by the server code:
print(data.decode('utf-8')+"\n")
Both the print itself causes a line break and then you also add another one.
In general you are assuming that each send has a matching recv. This assumption is wrong. TCP is a byte stream and not a message stream and the payloads from multiple send might be merged together to reduce the overhead of sending and it might also cause a "split" into a single "message".
This is especially true when sending traffic between machines since the bandwidth between the machines is less than the local bandwidth and the MTU of the data layer is also much smaller.
Given that you have to first collect your "messages" at the server side. Only after you've got a complete "message" (whatever this is in your case) you should decode('utf-8'). Otherwise your code might crash when trying to decode a character which has a multi-byte UTF-8 encoding but where not all bytes were received yet.

Why does sender IP address increment in Scapy?

I am trying to make a TCP packet that is sent to my other computer 500 times. I have created this code:
from scapy.all import *
from scapy.utils import rdpcap
#Create your own packets
data = 'This is a test'
myPacket = Ether(src="00:E0:4C:00:02:42",dst="00:E0:4C:01:08:99")/IP(src="169.254.162.71/16",dst="169.254.208.208/16")/TCP()/Raw(load=data)
print(myPacket.show())
for i in range (0,500):
sendp(myPacket, iface="Ethernet 4") # sending packet at layer 2
The issue is that when I run this code, the computer receives packets with an incrementing Source IP and the Destination IP is wrong, for some reason:
Any help fixing this would be appreciated.
The /16 in your addresses is called a netmask in CIDR notation. It means that your adresses are subnets that include all possible addresses between 169.254.0.0 and 169.254.255.255. (Same for the source IP)
See https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing and https://en.wikipedia.org/wiki/Private_network
Scapy is going to send 256x256x256x256 (accounting for both sr and dst) packets with all possible addresses, starting as you saw with the 0.0 ones. You just need to remove the /16.

Gnome terminal prints broken characters with packet sniffer

I have written a basic network packet sniffer with Python. When the packets comes, the program prints broken characters in my gnome-terminal.
Program codes:
#!/usr/bin/python
import socket
import struct
import binascii
s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, 8)
i = 1
while True:
pkt = s.recvfrom(2048)
ethhead = pkt[0][0:14]
eth = struct.unpack("!6s6s2s",ethhead)
print "--------Ethernet Frame %d------" % i
print "Destination MAC: ", binascii.hexlify(eth[0])
print "Source MAC: ", binascii.hexlify(eth[1])
binascii.hexlify(eth[2])
ipheader = pkt[0][14:34] #next 20 bytes
ip_hdr = struct.unpack("!8sB3s4s4s",ipheader)
print "-----------IP------------------"
print "TTL :", ip_hdr[1]
print "Source IP", socket.inet_ntoa(ip_hdr[3])
print "Destination IP", socket.inet_ntoa(ip_hdr[4])
tcpheader = pkt[0][34:54] #extracts next 20 bytes
tcp_hdr = struct.unpack("!HH9ss6s",tcpheader)
print "---------TCP----------"
print "Source Port ", tcp_hdr[0]
print "Destination port ", tcp_hdr[1]
print "Flag ",binascii.hexlify(tcp_hdr[3])
print "\n\n"
i += 1
print pkt[0][54:]
The sample output:
Sample Output Picture
I had set Terminal>Set character Encoding>Unicode(UTF-8) but it did not work either.
I am using Kali Linux 1.1.0, Gnome Terminal v 3.4.1.1.
Unfotunately, many protocols such as SSH and HTTPS use encryption and show characters that don't exist in ASCII or UTF-8. Your terminal will not be able to show these. This is because things like passwords and data should be hidden so that people can't do MITM nearly as easily. Try Wireshark, a graphical packet sniffer, it might work.
Bytes in the range 128-255 do not generally form valid UTF-8 strings. Even if the payload is encoded in UTF-8, there is no guarantee that packet boundaries will coincide with code point boundaries.
Perhaps as a workaround you would like to render the packets as e.g. ISO-8859-1 strings, or maybe even (gasp) offer an option to specify an encoding. The only change you need is pkt[0][54:].decode(encoding) - if there ever is a packet containing only complete, valid UTF-8 sequences, mentally decoding it from this output should be possible with a bit of training.

Python socket server receiving duplicate data

I have a raspberry running a server that communicates with a server on my laptop. I've done this through simple socket connections on python.
Like so:
server
HOST = "192.168.0.115"
PORT = 5001
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST,PORT))
s.listen(1)
conn, addr = s.accept()
while conn:
data = conn.recv(1024)
print data
if not data:
break
conn.close()
client
__init__(self,addr,port,timeout):
self.addr = addr
self.port = port
self.timeout = timeout
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((self.addr,self.port))
#in a different file the call to send is made, passes list object as a parameter
send(self,data):
if self.socket:
self.socket.send(str(data))
setting a print statement in the client code results in (x,y,z), which is the expected output. However, upon receiving the data on server it appears in a pattern:
(x,y,z)(x,y,z)
(x,y,z)
(x,y,z)
(x,y,z)(x,y,z)
...
Why is the data being received as duplicates? Is it a property of TCP? If so, how can I counter this to receive the data as one sent string as I had initially.
TCP sends data as a stream. You can write data to that stream, and you can receive data from that stream. The important thing is that while it can be the case that one send corresponds to one receive, that's not at all guaranteed to be the case. You can send a big chunk and receive it in a bunch of smaller chunks, or you can send a bunch of smaller chunks and receive a big chunk, or anything in-between. You're in the latter situation.
To solve this, you need to layer some sort of framing protocol on top of TCP. There's two primary ways you could do this:
Prefix each message with the length of the message and then read that many bytes.
Put a delimiter between each message.
For your purposes (sending plain text without newlines), the latter with a newline as a delimiter would probably be fine. You can probably figure out how to do that, but essentially, do this repeatedly:
Receive some data.
Append that data to a buffer.
Search for a newline and process the buffer up to that point. Repeat this step until there are no more newlines.
If all you're doing is printing, you can replace all that by just looping, receiving from the socket then writing to stdout.

How to send bytes using python (example please!)

I'm trying to create a simple thingermajigger in python at the moment just to test out sending UDP packets over a socket. I think that I'm getting my script perfectly fine other than using the socket.sendto command. I keep getting errors regarding the portion where "bytes" would go... either TypeError: an interget is required, or when I make it an interget TypeError: a string is required. Could someone provide me with an example of how to send a byte?
the point in my script where I'm getting the error is as follows... please fill out an example as well as a possible explanation / documentation for a newbie.
#full script as requested
import socket
import random
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
butes = random._urandom(1024)
#originally found this as a way to generate bytes to send, but it didn't work out
print("target IP: ")
ip = input()
print("port: ")
port = input()
while 1:
sock.sendto(butes, (ip, port))
print("Sent %s amount of packets to %s at port %s." % (sent,ip,port))
sent += 1
In your posted code, port is a str, you should use port = int(input())
Aside: b'0x2E' which you had in the original question is 4 characters. If you mean chr(0x2E) you can also write '\x2E'

Categories

Resources