Windows host can't receive UDP packets from WSL-2 guest - python

I'm trying to have a simple UDP echo client/server communicate with each other. The client program (which runs in the host Windows) sends packets to the server (which runs in WSL-2), and the server receives them, but the server's reply is never reaches the client.
import sys
from socket import *
from select import select
client = sys.argv[1].startswith("c")
host = sys.argv[2] if len(sys.argv) > 2 else "127.0.0.1"
port = 8080
sd = socket(AF_INET, SOCK_DGRAM)
def poll():
readable, writable, errorset = select([sd], [sd], [sd], 0)
return sd in readable
if client:
sd.connect((host, port))
sd.setblocking(0)
sd.send(b"Hello!")
while not poll():
pass
data, addr = sd.recvfrom(65535)
print(f"RECV {addr} => {data}")
else:
sd.bind((host, port))
print(f"Listening on {host}:{port}")
sd.setblocking(0)
sd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
while True:
while poll():
data, addr = sd.recvfrom(65535)
print(f"RECV {addr} => {data}")
sd.sendto(data.decode("utf-8").upper().encode("utf-8"), addr)
The output on Windows:
udpecho.py client 172.25.154.133
The output on Linux:
$ python3 udpecho.py server 172.25.154.133
Listening on 172.25.154.133:8080
RECV ('172.25.144.1', 57661) => b'Hello!'
And now I'm stumped. TCP connections work ok so it must only be a UDP thing, but I don't know what to try next.
Running Windows 10 Home edition and hosting Ubuntu-20.04 in WSL 2.

This sounds like this Github issue, where UDP packets smaller than 12 bytes don't make it from WSL2 to the host Windows interface.
If so, then a reported workaround is to turn off transmission checksumming in WSL2 via:
ethtool -K eth0 tx off
It sounds like this may be a Hyper-V networking issue that can be reproduced outside of WSL2, and the Microsoft team says it is under investigation.

Related

I want to create the simplest python socket server for chatting on AWS EC2

Server code:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('', 81))
client = []
print('Start Server')
while 1:
data, addres = sock.recvfrom(1024)
print(addres[0], addres[1])
if addres not in client:
client.append(addres)
for clients in client:
sock.sendto(data, clients)
Client code:
import socket
import threading
def read_sok():
while 1 :
data = sor.recv(1024)
print(data.decode('utf-8'))
server = '54.236.40.62', 81 # Public IP
alias = input()
sor = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sor.bind(('', 0))
sor.sendto((alias+' Connect to server').encode('utf-8'), server)
potok = threading.Thread(target= read_sok)
potok.start()
while 1 :
mensahe = input()
sor.sendto(('['+alias+']'+mensahe).encode('utf-8'), server)
The server OS is the linux ubuntu(third in quick start).
Python 3.10.6 is on the server. 3.11.1 on the client.
The server must resend incoming message to everyone clients, which have ever sent messages to it(including the client, who sent this message). When everything is ok, the client sends a message to the server and receives it back.
The problem is that the client(on my PC) can't interact with the sever. It just can't see the server. The client sends the message to the server and does not receive the message(the same situation when the server is turned off or the IP is incorrect for it).
1)These codes work fine if they are on the same PC or on the same network.
2)I didn't forget about security group settings. Port 81 is opened as 80. I started apache2 default page through 80 and it works well in the browser. I also tried using port 80(which certainly works well) for python server(unsuccessful).
3) I know that I can't use public IP for sock.bind(('', 81)). I tried using both sock.bind(('', 81)) and sock.bind(('Private_IP', 81)) cases.
4) I also used ports like 12345 and etc.
I would be grateful for any advice:)

How can i connect two computers with python socket?

im new here!
I have a problem with connection between two computers connected with different wi-fi's. After about 20 seconds i get information that connection can't be done.
There is my code:
SERVER:
from socket import *
lista = ['computer']
s = socket(AF_INET, SOCK_STREAM)
port = 21312
s.bind(('my ipv4', port))
s.listen(5)
while True:
for i in range (0, len(lista)):
a = str(lista[i]).encode()
c, addr = s.accept()
print("CONNECTION WITH",addr)
c.send(a)
print(a)
c.close()
CLIENT:
import socket
from socket import *
port = 21312
while True:
s = socket(AF_INET,SOCK_STREAM)
s.connect(('my ipv4', port))
odebrana = (s.recv(1024))
decoded = odebrana.decode()
print(decoded)
s.close()
Likely you are experiencing an issue because your server sits behind a Network Address Translator (NAT). This way your client cannot use the server's IP directly since it is not reachable. There are a few ways around it.
The easiest and not very practical one is: get both machines in the same network, then it should work.
Get a public IP address for the server. You can do that by hosting it on a cloud server that provides you with a public IP, e.g., aws, azure, google cloud etc.
In the old days we used hamachi to get a VPN that would connect both machines. Then they can identify each other over that VPN. Simply turn on hamachi (or any other VPN solution), run your server, then from your client (connected to the VPN), use the VPN's server IP (hamachi will provide you with one when you setup a network).
Disclaimer: I have not used hamachi in about 15 years, but just went through the process because of one of the comments below.
Seems like you can create an account, then once you turn it on you should see your v4 and v6 addresses as shown below:
Highlighted is my v4 address. I suspect you need to create a network, join both PCs in the same network and then use hamachi's IP to emulate behaviour as if they were connected via LAN.
So I faced the similar problem while sending image files between 2 computers using python sockets. I solved the issue by following this way:
First I completed writing the connection code of both server.py and client.py
Note: server.py should be in one computer and client.py should be in another computer.
server.py
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
print(host)
server.bind((host, 12000))
server.listen()
client_socket, client_address = server.accept()
file = open('server_image.jpg','wb')
image_chunk = client_socket.recv(2048)
while image_chunk:
file.write(image_chunk)
image_chunk = client_socket.recv(2048)
file.close()
client_socket.close()
client.py
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # AF_INET = IP, SOCK_STREAM = TCP
server_host = 'LAPTOP-1231' # Replace this hostname with hostname printed in server.py
client.connect((server_host, 12000)) # 127.0.0.1
file = open('That_Sinking_Feeling_27.jpg', 'rb')
image_data = file.read(2048)
while image_data:
client.send(image_data)
image_data = file.read(2048)
file.close()
client.close()
Now you should add the image in the directory where client.py is located, so that you can send it to another computer (server). Rename it to img.jpg
Then, you need to run server.py in your another computer. It will print the hostname in terminal. Then copy that hostname and paste it in client.py (server_host = hostname_from_server)
Then run client.py
Finally the image will be transferred to new computer (server)

Python Multicast between client and server will only work with router between them [duplicate]

I have a Windows machine where I have two scripts that send and receive messages via UDP multicast (on the same machine). I have a C and Python3 implementation of this. The Python3 one looks like this:
sender.py
import socket
MCAST_GRP = '239.1.1.1'
MCAST_PORT = 1234
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
print("Sending")
sock.sendto(bytearray("str()", "utf-8"), (MCAST_GRP, MCAST_PORT))
data, address = sock.recvfrom(1024)
print('received %s bytes from %s' % (len(data), address))
print(data)
receiver.py
import socket
import struct
import sys
multicast_group = '239.1.1.1'
server_address = ('', 1234)
# Create the socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Bind to the server address
sock.bind(server_address)
# Tell the operating system to add the socket to the multicast group
# on all interfaces.
group = socket.inet_aton(multicast_group)
mreq = struct.pack('4sL', group, socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
# Receive/respond loop
while True:
print('\nwaiting to receive message')
data, address = sock.recvfrom(1024)
print('received %s bytes from %s' % (len(data), address))
print(data)
print('sending acknowledgement to', address)
sock.sendto(bytearray("ack", "utf-8"), address)
I have another physical device hooked up to the same machine but I cannot receive any messages from it with my programs. I can see that Wireshark is seeing the messages from the other physical device, these messages are coming over the eth0 interface to the same IP and Port. I know that the traffic generated by my scripts is on the VirtualBox Host-Only Network. I am not sure if that could cause the issue of me not seeing the UDP multicast messages from the external device.
I have tested it on a Linux machine as well (latest kali version) but could not receive any messages from the external device as well.
If I am missing some information, please let me know.
EDIT 1:
My setup is as follows:
I am running a native Windows 10 machine. To this machine is a device connected that is running some OS I don't know. I am only able to send and receive messages from it. I can send Ethernet, TCP, and IPv4 packets over the physical ethernet port on my Windows 10 machine by specifying the software I am using for this to use eth0 and a defined IP(v4) address I assigned to that port in the network adapter settings (192.168.1.100)
The scripts are running on the same Windows 10 machine that is also connected to the device. They are sending on this interface VirtualBox Host-Only Network but I don't know why. I did not configure anything like this. I assume that the interface should not be a problem because that is how UDP Multicast works (I am not sure of that so if I am mistaken please let me know!)
A sample output of the sender looks like this:
Sending
received 3 bytes from ('192.168.56.1', 3000)
b'ack'
Process finished with exit code 0
and the receiver:
waiting to receive message
received 5 bytes from ('192.168.56.1', 55132)
b'robot'
sending acknowledgement to ('192.168.56.1', 55132)
waiting to receive message
I hope that clarifies the setup. If there is still information missing please let me know!
As covered in https://www.tldp.org/HOWTO/Multicast-HOWTO-6.html, the sockets API requires that you identify the interface as well as the multicast address/port you want to use.
By not specifying this in your sample code, you have left this down to the OS to pick and it has picked a VirtualBox Host-Only Network. Unfortunately this type of network is limited to VMs running on the Windows machines.
To fix it, you need to identify the interface that you want to use for the multicast and pass that in to your sending and receving code. For example:
sender.py
sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(MCAST_IF_IP))
receiver.py
mreq = struct.pack('4s4s', group, socket.inet_aton(MCAST_IF_IP))
where MCAST_IF_IP is the IP address of the interface that you want to use.

How to send socket message when Server has a preset initial response?

I'm making python binds for Blackmagic's Ethernet Control Protocol ( as documented in https://documents.blackmagicdesign.com/UserManuals/HyperDeckManual.pdf?_v=1528269592000 , page 60). Simple socket connection seems to fail however, because every commands gets rejected with the server's greeting.
This protocol documents how software can communicate with certain blackmagic devices, in this case, Blackmagic's hyperdeck, the device runs a TCP server constantly listening on port 9993, on cmd I can simply telnet to it and issue commands, you'd it expect it to be as straightforward in python, however every command gets ignored for the server's greeting message, the device's information. I have been doing socket's for at least 3 months now and i've tried several methods of code, and all seem to fail.
For the most trivial test i've used:
import socket
HOST = "device's ip"
PORT = 9993
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall(b'play')
data = s.recv(1024)
print(data)
and a modified version to try to repeat the command:
import socket
import time
HOST = "device's ip"
PORT = 9993
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall(b'play')
data = s.recv(1024)
time.sleep(2)
s.sendall(b'play')
It should start video playback, as documented, and as occurs when I issue the command thru telnet, however the command is completely ignored and data always equals to: b'500 connection info:\r\nprotocol version: 1.9\r\nmodel: HyperDeck Studio Mini\r\n\r\n' , the server's greeting message in byte form, it should instead be 200 ok or some sort of error / acknowledged message, as documented.
This is incredibly annoying and i've thought of using subprocess and issuing commands thru cmd as an alternative, but something tells me there's an easier workaround.

Python socket only accepting local connections

Server:
import socket
host = ""
port = 4242
backlog = 5
size = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host,port))
s.listen(backlog)
client, address = s.accept()
while 1:
data = client.recv(size)
if data:
client.send(data)
print(data.decode("utf-8"))
Client:
import socket
import sys
host = sys.argv[1]
port = 4242
size = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
while True:
line = input("What to say: ")
s.send(line.encode("utf-8"))
Well, I'm a bit confused here. I'm beginning to learn about sockets, so I started out on a simple echo server. The code I've posted above works beautifully when the server is running on Arch Linux or Ubuntu. When it's on Windows 7 however, it only accepts local connections. The thing is, I'm not running a firewall. I'm not sure if Python has a separate WinSock implementation or what, but I'm confused! Please, if you would, I'm quite aware that this is terribly designed (only accepts on client!), but I just want to know why Windows won't accept remote connections.
If it helps, on Arch and Ubuntu, I'm running on Python 3.1, while on Win 7 it's on 3.2.
Sounds like host='' is defaulting to bind to localhost (127.0.0.1) under Win 7 (I don't have access to a Win 7 machine at the moment).
To make your server reachable on all (IPv4) interfaces on the host, this should work on Linux, Windows, Mac, etc:
host = '0.0.0.0'
s.bind((host, 8080))
To verify which address the socket is binding to you can do this:
>>> s.getsockname()
('0.0.0.0', 8080)
As the documentation for Socket states:
Some behavior may be platform dependent, since calls are made to the operating system socket
APIs.
I'm not familiar with Win32 network programming, but I would hazard a guess that it's probably a implementation specific behavior that is triggered when you create a socket without binding it to an address.
My suggestion is move up an abstraction level and use SocketServer.

Categories