From c9a10be5baeef9406dadd244d308c163ea026471 Mon Sep 17 00:00:00 2001 From: Neil Booth Date: Tue, 29 Nov 2016 20:20:18 +0900 Subject: [PATCH] Introduce incoming buffer size limit - incoming buffered network requests limited to 150,000 bytes which I believe is ample for a genuine client - if exceeded, the connection is dropped - raise outgoing data limit for RPC connections to 5 MB - expect sessions calls can be long and connection is implicitly trusted - similarly raise incoming buffered data limit to 5 MB for RPC connections --- electrumx_rpc.py | 2 ++ lib/jsonrpc.py | 13 +++++++++++++ server/protocol.py | 1 + 3 files changed, 16 insertions(+) diff --git a/electrumx_rpc.py b/electrumx_rpc.py index 192f887..47cb8f6 100755 --- a/electrumx_rpc.py +++ b/electrumx_rpc.py @@ -23,6 +23,8 @@ from server.protocol import ServerManager class RPCClient(JSONRPC): async def send_and_wait(self, method, params, timeout=None): + # Raise incoming buffer size - presumably connection is trusted + self.max_buffer_size = 5000000 self.send_json_request(method, id_=method, params=params) future = asyncio.ensure_future(self.messages.get()) diff --git a/lib/jsonrpc.py b/lib/jsonrpc.py index 23bcd93..f50a9a9 100644 --- a/lib/jsonrpc.py +++ b/lib/jsonrpc.py @@ -96,6 +96,8 @@ class JSONRPC(asyncio.Protocol, LoggedClass): # connection. The request causing it is logged. Values under # 1000 are treated as 1000. self.max_send = 0 + # If buffered incoming data exceeds this the connection is closed + self.max_buffer_size = 150000 self.anon_logs = False def peername(self, *, for_log=True): @@ -122,6 +124,17 @@ class JSONRPC(asyncio.Protocol, LoggedClass): decode_message for handling. ''' self.recv_size += len(data) + + # Close abuvsive connections where buffered data exceeds limit + buffer_size = len(data) + sum(len(part) for part in self.parts) + if buffer_size > self.max_buffer_size: + self.logger.error('read buffer of {:,d} bytes exceeds {:,d} ' + 'byte limit, closing {}' + .format(buffer_size, self.max_buffer_size, + self.peername())) + self.transport.close() + + # Do nothing if this connection is closing if self.transport.is_closing(): return diff --git a/server/protocol.py b/server/protocol.py index efca69b..d0abf3f 100644 --- a/server/protocol.py +++ b/server/protocol.py @@ -923,3 +923,4 @@ class LocalRPC(Session): self.handlers = {cmd: getattr(self.manager, 'rpc_{}'.format(cmd)) for cmd in cmds} self.client = 'RPC' + self.max_send = 5000000