MagicStack / MagicStack/uvloop
Silently closes UDP socket
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Cython
- Sterne
- 11.9k
- Forks
- 616
- PR-Merge-Kennzahlen
- Keine gemergten PRs in 30 T.
Beschreibung
- 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

Beitragsleitfaden
Für dieses Repository ist kein Beitragsleitfaden indexiert
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginne damit, den UDP-Reproducer des Issues mit uvloop und vanilla asyncio auszuführen, wobei der Fokus auf create_datagram_endpoint und transport.sendto mit dem Zielport 0 liegt. Vergleiche den Socket-Zustand und das anschließende recv-Verhalten nach dem Senden. Erledigt bedeutet, dass ein ungültiges UDP-Ziel den Transport nicht stillschweigend schließt und das Verhalten durch einen Regressionstest dokumentiert ist.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- python
- Bereich
- networking
- Issue-Typ
- Bug
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Aktivitätsstatus
- Veraltet
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 35/100