UDP fragmentation in Python standard library - python

Am I right that UDP fragmentation should not be handled by developer himself in Python?
Am I right that I'll get my UDP packet with all originally sent data and not just one fragment of it?
while True:
data, addr = s.recvfrom(65535)
# Process packet

You will get the whole datagram that was sent through another UDP socket in one send or write operation. UDP is not stream oriented like TCP.

Related

How to send packets in scapy from a specific socket?

I am trying to send some packet through scapy by creating a socket. I want to send the packets through the socket which I created. How can I accomplish this
here is some code which I tried
pkt = "\x00\x1c\x7fb\xb5\xfd\x00PV\xb8\x08\x9f\x08\x00E\x00\x000/t\x00\x00\x80\x11\x00\x00\n\xe7\xa0\xc6\n\xe7\x922\xd2\xb4\x05\xdc\x00\x1cH\xf4\t\x8d\x01\x00\x01\x01\x00\x10\xff\xff\xfe\xd4\x00\x00\x00\x00\xb2\x1a=\x0f"
Socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
Socket.bind(('',udp_sport))
S = Socket.connect_ex(("10.146.144.51",1803))
Socket.settimeout(10)
sendp(pkt,socket=S)
I have seen in scapy library that there is an option to use Socket in sendp. How can I use this to send? Please help.
You can use a StreamSocket as a wrapper for your socket. See https://scapy.readthedocs.io/en/latest/layers/tcp.html?highlight=streamsocket#using-the-kernel-s-tcp-stack
In your case:
ss=StreamSocket(s,Raw)
ss.send(...)
Note: in your example, you are using sendp(). This means a layer 2 packet. This won't work with the layer 3 socket that you have created: make sure the packet you are sending is L3.

Python sendto doesn't seem to send

I am new to Python and trying to send a byte array as a raw packet using a socket. My IP is 192.168.0.116 and the device I am sending this to is 192.168.0.64. This client device is a microcontroller based unit which is executing my code to simply sniff the Ethernet packets and check for a particular pattern. I am using UDP packets and tried the client side firmware by using 'Ostinato' in my PC to send a raw UDP packet. I am using Wireshark to monitor the network packet flow. The client seems to work fine with packets sent by Ostinato.
However when I try to send the same packet with Python (using raw packets as follows), it doesn't seem to spit out the bytes as I cant see anything on Wireshark nor the client get any data. But the return value from sendto() is correct. So it seems that Python feeds the byte array to a buffer to be sent (by OS?) but stops there.
import socket
CLNT_UDP_IP = '192.168.0.64'
CLNT_UDP_PORT = 5005
svr_sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
send_data = [0x00, 0x11...]
send_data_arr = bytearray (send_data)
svr_sock.bind (('192.168.0.116',0))
bytes_send = svr_sock.sendto (send_data_arr, (CLNT_UDP_IP, CLNT_UDP_PORT))
svr_sock.close()
I have taken out the try-except blocks for clarity.
Another thing I noted is that when the socket is closing, it takes a bit of time. If I comment out the sendto statement, it exits immediately. So it seems like the socket close is trying to flush the send buffers, which failed to send the packet.
Any ideas?
Ilya is right, you should be opening a UDP socket with
socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
You're binding to port 0, which is invalid. If this is not an inbound port, you don't need to bind it. This may explain why your sendto call is blocking.
The send_data array should contain only your data, not "the full ethernet packet".
The send_data array must be under the MTU size for your network, otherwise it may be dropped silently. It varies but under 1300 should work, over 1500 almost certainly won't work.

Can't receive UDP packet in Python

I'm having trouble receiving a UDP packet sent from an FPGA in a python program. I've checked similar questions and did the following:
Checked that Wireshark can the see UDP packet
Disabled windows firewall in PC
Used sock.bind() since it's UDP packets
Manually set the destination MAC address on Ethernet frame since FPGA does not support ARP
Set dest IP to broadcast 10.10.255.255 for testing, no packets received
Set the UDP checksum of the packet from the sender to 0x0000
Here's the python receiver code:
import socket
import sys
UDP_IP = "10.10.10.87"
UDP_PORT = 4660
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))
print("Socket: "+str(sock.getsockname()))
while True:
data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
print(data)
print(addr)
sys.stdout.flush()
When tested against another python script that sends to 10.10.10.87:4660
(from another PC in the 10.10.10 network) the receiver script works fine. I've even tried to recreate the UDP pcket byte-by-byte in the FPGA from packets that I know are received OK (Differences are source IP, port & MAC, checksums (disabled), identification).
Here's the output for both packets from Wireshark:
Wireshark UDP packet (Python UDP packet that gets received OK on the left, Xilinx FPGA packet that is not received by python on the right)
I'm not sure what else to try. Any help would be appreciated.
Apparently the IPv4 header checksum from an FPGA calculation was wrong. It can get confusing to follow since the TTL (Time to Live) changes on a router hop, and the new TTL will also change the IPv4 header, forcing a new checksum per hop until it gets to Wireshark on the receiver end. By default Wireshark has IPv4 checksum validation disabled (as can be seen in the question screenshot), the answer is easier to spot with validation on.
I set the IPv4 checksum during packet construction to zero (x0000). It gets recalculated correctly at the router, and with the correct checksum Python can receive the packet.
I also tested a direct connection (without router) from the FPGA to the host PC. The IPv4 header also gets recalculated correctly (I'm not sure where, probably the PC's NIC?)
Hope this is useful to someone with similar problems.

Python client server how UDP is supposed to work?

I have a client-server "snake" game working really well with TCP connections, and I would like to try it the UDP way.
I wonder how it is supposed to be used ? I know how UDP works, how to make a simple ECHO example, but I wonder how to do the following :
For instance with TCP, every TICK (1/15 second) server sends to the client the new Snake head position.
With UDP, am I supposed to do something like this :
Client SIDE :
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
serverAddr = (('localhost', PORT))
while 1:
client.sendto('askForNewHead', serverAddr)
msg, addrServer = client.recvfrom(1024)
game.addPosition(msg)
Server SIDE :
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind((HOST, PORT))
while 1:
data, addr = server.recvfrom(1024)
server.sendto(headPosition, addr)
So here Client has to ask server to get the new head position, and then server sends the answer. I managed to make it work this way, but I can't figure out if it is a good way of doing.
Seems weird that client has to ask udp for an update while with my TCP connection, client has just to wait untill he receives a message.
There are differences between TCP and UDP but not the way you describe. Like with TCP the client can recvfrom to get messages from the server without asking each time for new data. The differences are:
With TCP the initial connect includes a packet exchange between client and server. Unless the client socket was already bound to an IP and port it will be bound to the clients IP and a free port will be allocated. Because of the handshake between client and server the server knows where to contact the client and thus can send data to the packet without getting data from the client before.
With UDP there is no initial handshake. Unless already bound, the socket will be bound to clients IP and a free port when sending the first packet to the server. Only when receiving this packet the server knows the IP and port of the client and can send data back.
Which means, that you don't need to 'askForNewHead' all the time. Instead the client has to send only a single packet to the server so that the server knows where to send all future packets.
But there are other important differences between TCP and UDP:
With UDP packets may be lost or could arrive in a different order. With TCP you have a guaranteed delivery.
With UDP there is no real connection, only an exchange of packets between two peers. With TCP you have the start and end of a connection. This is relevant for packet filters in firewalls or router, which often need to maintain the state of a connection. Because UDP has no end-of-connection the packet filters will just use a simple timeout, often as low as 30 seconds. Thus, if the client is inside a home network and waits passively for data from server, it might wait forever if the packet filter closed the state because of the timeout. To work around this data have to be transmitted in regular intervals so that the state does not time out.
One often finds the argument, that UDP is faster then TCP. This is plain wrong. But you might see latency problems if packets get lost because TCP will notice packet loss and send the packet again and also reduce wire speed to loose less packets. With UDP instead you have to deal with the packet loss and other congestion problems yourself. There are situations like real time audio, where it is ok to loose some packets but low latency is important. These are situations where UDP is good, but in most other situations TCP is better.
UDP is different to TCP, and I believe with python the client does have to ask for an update from the server.
Although it is fun to learn and use a different way of communicating over the internet, for python I would really recommend sticking with TCP.
You don't have to ask the server for a update. But since UDP is connection-less the server can send head-positions without being asked. But the client should send i'm-alive-packets to the server, but this could happen every 10 seconds or so.

Unable to send UDP packets to local port with python, fails checksum according to WireShark

I've been pulling my hair out over this one. I'm trying to write a SOCKS5 server in Python to tunnel UDP traffic. I bind to a port, and receive data fine. I then parse the SOCKS5 UDP header (not the typical UDP header), and forward the datagram to the requested endpoint.
All is good. I then listen for a response from the endpoint (resending if timeout), and get a response. Great!
Here is where I'm losing my mind-
I get the datagram back from the endpoint. I re-encapsulate the returned datagram according to the SOCKS5 RFC, which is the same UDP header as before, except I have now changed the destination address and port to the original caller. I use:
sock_client = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock_client.sendto(packed_datagram, (self.client_ip, self.client_port))
to send the datagram back to client. The client never receives the reply! Ever!
Looking at WireShark, it says this: Header checksum: 0x0000 [incorrect, should be 0xcd1f (may be caused by "IP checksum offload"?)]
Shouldn't the python socket implementation, with socket.DGRAM set, automatically pack my data correctly in a UDP header and calculate the appropriate checksum? Why is it being set to 0x0000? I checked the payload in hex, the checksum is indeed set wrong. What the heck is going on?
The checksum calculation is done by the drivers in the operating system. In may cases, the calculation is done by the network card itself. IIRC, Wireshark grabs local packets just before they are handed off to the network stack. It's common to checksum errors for all locally generated packets.
I was not following two pieces of the SOCKS5 spec accurately.
A UDP association terminates when the TCP connection that the UDP
ASSOCIATE request arrived on terminates.
I was terminating the TCP socket immediately after completing UDP relay handshake. TCP must stay open until the back-and-forth is finished.
When a UDP relay server receives a reply datagram from a remote
host, it MUST encapsulate that datagram using the above UDP request
header, and any authentication-method-dependent encapsulation.
I was using the client's IP and port as the values in the datagram. It needs to be the remote server's IP and port, essentially the UDP header encapsulation is a clone of what the client passed in.
With these two issues solved, the SOCKS5 server works as anticipated.
If I understand your part of code correctly you create a new socket to send the data back to the client. Thus this will be a new socket with a random source IP, e.g. from the view of the client you have the following packet flow:
client_ip:client_port -> socks5_ip:socks_port
client_ip:client_port <- socks5_ip:random_port
The client has probably a connected socket to the socks5 server and thus expects replies coming from socks5_ip:socks_port, not the random_port.
So you should not create a new socket to the client but instead reply using the existing socket where you received the data from the client.
turn off tx-checksumming using the linux command:
ethtool -K eth0 tx off
OR use this function to calculate the checksum
def checksum(data):
s = 0
n = len(data) % 2
for i in range(0, len(data)-n, 2):
s+= ord(data[i]) + (ord(data[i+1]) << 8)
if n:
s+= ord(data[i+1])
while (s >> 16):
s = (s & 0xFFFF) + (s >> 16)
s = ~s & 0xffff
return s
Where the data is the pseudo header

Categories