From 00168130ef4f6ef1e86fb09e16eed7cda1467beb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeremy=20Lain=C3=A9?= Date: Tue, 8 Jan 2019 23:39:34 +0100 Subject: [PATCH] Improve UDPTransport.sendto address validation (fixes: #214) When UDPTransport.sendto is called with a destination address, only perform the validation once and store the result in an LRU cache. Also store some of the socket's properties (family, proto, type) as integers to avoid repeatedly fetching these properties and converting them to integers. --- uvloop/handles/udp.pxd | 3 +++ uvloop/handles/udp.pyx | 34 +++++++++++++++++++++------------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/uvloop/handles/udp.pxd b/uvloop/handles/udp.pxd index 4f03650a..2e95ac24 100644 --- a/uvloop/handles/udp.pxd +++ b/uvloop/handles/udp.pxd @@ -1,6 +1,9 @@ cdef class UDPTransport(UVBaseTransport): cdef: object sock + int sock_family + int sock_proto + int sock_type UVPoll poll object address object buffer diff --git a/uvloop/handles/udp.pyx b/uvloop/handles/udp.pyx index 81ad198c..8380b229 100644 --- a/uvloop/handles/udp.pyx +++ b/uvloop/handles/udp.pyx @@ -1,4 +1,5 @@ -import socket +import functools + cdef class UDPTransport(UVBaseTransport): @@ -17,6 +18,9 @@ cdef class UDPTransport(UVBaseTransport): socket_inc_io_ref(sock) self.sock = sock + self.sock_family = sock.family + self.sock_proto = sock.proto + self.sock_type = sock.type self.address = r_addr self.poll = UVPoll.new(loop, sock.fileno()) self._finish_init() @@ -143,18 +147,8 @@ cdef class UDPTransport(UVBaseTransport): raise ValueError( 'Invalid address: must be None or {}'.format(self.address)) - if addr is not None and self.sock.family != socket.AF_UNIX: - addrinfo = __static_getaddrinfo_pyaddr( - addr[0], addr[1], - uv.AF_UNSPEC, self.sock.type, self.sock.proto, 0) - if addrinfo is None: - raise ValueError( - 'UDP.sendto(): address {!r} requires a DNS lookup'.format( - addr)) - if addrinfo[0] != self.sock.family: - raise ValueError( - 'UDP.sendto(): {!r} socket family mismatch'.format( - addr)) + if addr is not None and self.sock_family != uv.AF_UNIX: + self._validate_address(addr) if self._conn_lost and self._address: if self._conn_lost >= LOG_THRESHOLD_FOR_CONNLOST_WRITES: @@ -188,3 +182,17 @@ cdef class UDPTransport(UVBaseTransport): # Ensure that what we buffer is immutable. self.buffer.append((bytes(data), addr)) self._maybe_pause_protocol() + + @functools.lru_cache() + def _validate_address(self, object addr): + addrinfo = __static_getaddrinfo_pyaddr( + addr[0], addr[1], + uv.AF_UNSPEC, self.sock_type, self.sock_proto, 0) + if addrinfo is None: + raise ValueError( + 'UDP.sendto(): address {!r} requires a DNS lookup'.format( + addr)) + if addrinfo[0] != self.sock_family: + raise ValueError( + 'UDP.sendto(): {!r} socket family mismatch'.format( + addr))