MagicStack / MagicStack/uvloop
Silently closes UDP socket
Personne n'a encore pris cette issue.
- Langage dominant
- Cython
- Étoiles
- 11.9k
- Forks
- 616
- Métriques de merge des PR
- Aucune PR mergée en 30 j
Description
- uvloop version: 0.14
- Python version: 3.8.2
- Platform: Linux
- Can you reproduce the bug with
PYTHONASYNCIODEBUGin env?: Yes - Does uvloop behave differently from vanilla asyncio? How?: Yes. See below
uvloop silently closes UDP socket when sending data to incorrect destination.
Test program:
import asyncio
import uvloop
# uncomment this line to check it with uvloop
#uvloop.install()
async def main():
loop = asyncio.get_event_loop()
transport, proto = await loop.create_datagram_endpoint(
asyncio.DatagramProtocol,
local_addr=("192.168.0.2", 0),
)
print(transport.get_extra_info('sockname'))
print("Before sending the message with None destination")
transport.sendto(b"deadbeef")
print("After sending the message with None destination")
await asyncio.sleep(0.1) # let asyncio closes internal socket
print("Before sending the message with incorrect port destination")
transport.sendto(b"deadbeef", ("45.83.128.251", 0))
print("After sending the message with incorrect port destination")
transport.close()
asyncio.get_event_loop().run_until_complete(main())
asyncio output:
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "", line 1, in
File "/root/.pyenv/versions/3.8.2/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
return future.result()
File "", line 14, in main
File "/root/.pyenv/versions/3.8.2/lib/python3.8/asyncio/selector_events.py", line 1056, in sendto
self._fatal_error(
File "/root/.pyenv/versions/3.8.2/lib/python3.8/asyncio/selector_events.py", line 703, in _fatal_error
self._loop.call_exception_handler({
AttributeError: 'NoneType' object has no attribute 'call_exception_handler'
uvloop output:
Then we can cut off first block with sending to None destination. And here we have NEW ONE differece in handling ip:port.
async def main():
loop = asyncio.get_event_loop()
transport, proto = await loop.create_datagram_endpoint(
asyncio.DatagramProtocol,
local_addr=("192.168.0.2", 0),
)
print(transport.get_extra_info('sockname'))
print("Please use `netstat -au` to see this socket really listening. I will wait 10 sec")
await asyncio.sleep(10)
print("Before sending the message with incorrect port destination")
transport.sendto(b"deadbeef", ("45.83.128.251", 0))
print("After sending the message with incorrect port destination")
print("Please use `netstat -au` to see this socket STILL really listening. I will wait 10 sec")
await asyncio.sleep(10)
transport.close()
When i run it with asyncio event loop all looks fine, socket still present.
When i run it with uvloop it silently closes, and also i can go into infinity wait on recv() call
As i know RFC describe that case as (https://tools.ietf.org/html/rfc8085#section-5.1):
A UDP sender SHOULD NOT use a source port value of zero. A source
port number that cannot be easily determined from the address or
payload type provides protection at the receiver from data injection
attacks by off-path devices. A UDP receiver SHOULD NOT bind to port
zero.
But i got real messages from the internet with that port. I will drop it in my application, but i think uvloop should not silently closes socket. It's very unexpected and differ from asyncio event loop.
Proof from Sentry (https://github.com/spumer/source-query-proxy):
next iteration of recv packet was failed, cause in previous we send response to zero port

Guide de contribution
Aucun guide de contribution indexé pour ce dépôt
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Commencez par exécuter le reproducteur UDP de l’issue avec uvloop et vanilla asyncio, en vous concentrant sur create_datagram_endpoint et transport.sendto avec le port de destination 0. Comparez l’état du socket et le comportement ultérieur de recv après l’envoi. C’est terminé lorsqu’une destination UDP invalide ne ferme pas silencieusement le transport et que le comportement est documenté par un test de régression.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- python
- Domaine
- networking
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- À l'abandon
- Clarté
- Plutôt claire
- Accessibilité débutants
- 35/100