ZMQ_MAXMSGSIZE option added

The new option allows user to guard against peers sending
oversized messages. Connection to peer sending oversized message
is dropped.

Signed-off-by: Martin Sustrik <sustrik@250bpm.com>
This commit is contained in:
Martin Sustrik 2011-03-02 09:00:36 +01:00
parent 4c7446211a
commit 5fcef1cac4
9 changed files with 72 additions and 7 deletions

View File

@ -311,6 +311,20 @@ Default value:: 100
Applicable socket types:: all, only for connection-oriented transports Applicable socket types:: all, only for connection-oriented transports
ZMQ_MAXMSGSIZE: Maximum acceptable inbound message size
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The options shall retrieve limit for the inbound messages. If a peer sends
a message larger than ZMQ_MAXMSGSIZE it is disconnected. Value of -1 means
'no limit'.
[horizontal]
Option value type:: int64_t
Option value unit:: bytes
Default value:: -1
Applicable socket types:: all
ZMQ_FD: Retrieve file descriptor associated with the socket ZMQ_FD: Retrieve file descriptor associated with the socket
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'ZMQ_FD' option shall retrieve the file descriptor associated with the The 'ZMQ_FD' option shall retrieve the file descriptor associated with the

View File

@ -319,6 +319,18 @@ Option value unit:: connections
Default value:: 100 Default value:: 100
Applicable socket types:: all, only for connection-oriented transports. Applicable socket types:: all, only for connection-oriented transports.
ZMQ_MAXMSGSIZE: Maximum acceptable inbound message size
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Limits the size of the inbound message. If a peer sends a message larger than
ZMQ_MAXMSGSIZE it is disconnected. Value of -1 means 'no limit'.
[horizontal]
Option value type:: int64_t
Option value unit:: bytes
Default value:: -1
Applicable socket types:: all
RETURN VALUE RETURN VALUE
------------ ------------

View File

@ -204,6 +204,7 @@ ZMQ_EXPORT int zmq_term (void *context);
#define ZMQ_BACKLOG 19 #define ZMQ_BACKLOG 19
#define ZMQ_RECOVERY_IVL_MSEC 20 /* opt. recovery time, reconcile in 3.x */ #define ZMQ_RECOVERY_IVL_MSEC 20 /* opt. recovery time, reconcile in 3.x */
#define ZMQ_RECONNECT_IVL_MAX 21 #define ZMQ_RECONNECT_IVL_MAX 21
#define ZMQ_MAXMSGSIZE 22
/* Send/recv options. */ /* Send/recv options. */
#define ZMQ_NOBLOCK 1 #define ZMQ_NOBLOCK 1

View File

@ -25,9 +25,10 @@
#include "wire.hpp" #include "wire.hpp"
#include "err.hpp" #include "err.hpp"
zmq::decoder_t::decoder_t (size_t bufsize_) : zmq::decoder_t::decoder_t (size_t bufsize_, int64_t maxmsgsize_) :
decoder_base_t <decoder_t> (bufsize_), decoder_base_t <decoder_t> (bufsize_),
destination (NULL) destination (NULL),
maxmsgsize (maxmsgsize_)
{ {
zmq_msg_init (&in_progress); zmq_msg_init (&in_progress);
@ -63,7 +64,13 @@ bool zmq::decoder_t::one_byte_size_ready ()
// in_progress is initialised at this point so in theory we should // in_progress is initialised at this point so in theory we should
// close it before calling zmq_msg_init_size, however, it's a 0-byte // close it before calling zmq_msg_init_size, however, it's a 0-byte
// message and thus we can treat it as uninitialised... // message and thus we can treat it as uninitialised...
int rc = zmq_msg_init_size (&in_progress, *tmpbuf - 1); int rc;
if (maxmsgsize >= 0 && (int64_t) (*tmpbuf - 1) > maxmsgsize) {
rc = -1;
errno = ENOMEM;
}
else
rc = zmq_msg_init_size (&in_progress, *tmpbuf - 1);
if (rc != 0 && errno == ENOMEM) { if (rc != 0 && errno == ENOMEM) {
rc = zmq_msg_init (&in_progress); rc = zmq_msg_init (&in_progress);
errno_assert (rc == 0); errno_assert (rc == 0);
@ -92,7 +99,13 @@ bool zmq::decoder_t::eight_byte_size_ready ()
// in_progress is initialised at this point so in theory we should // in_progress is initialised at this point so in theory we should
// close it before calling zmq_msg_init_size, however, it's a 0-byte // close it before calling zmq_msg_init_size, however, it's a 0-byte
// message and thus we can treat it as uninitialised... // message and thus we can treat it as uninitialised...
int rc = zmq_msg_init_size (&in_progress, size - 1); int rc;
if (maxmsgsize >= 0 && (int64_t) (size - 1) > maxmsgsize) {
rc = -1;
errno = ENOMEM;
}
else
rc = zmq_msg_init_size (&in_progress, size - 1);
if (rc != 0 && errno == ENOMEM) { if (rc != 0 && errno == ENOMEM) {
rc = zmq_msg_init (&in_progress); rc = zmq_msg_init (&in_progress);
errno_assert (rc == 0); errno_assert (rc == 0);

View File

@ -26,6 +26,7 @@
#include <algorithm> #include <algorithm>
#include "err.hpp" #include "err.hpp"
#include "stdint.hpp"
#include "../include/zmq.h" #include "../include/zmq.h"
@ -180,7 +181,7 @@ namespace zmq
{ {
public: public:
decoder_t (size_t bufsize_); decoder_t (size_t bufsize_, int64_t maxmsgsize_);
~decoder_t (); ~decoder_t ();
void set_inout (struct i_inout *destination_); void set_inout (struct i_inout *destination_);
@ -196,6 +197,8 @@ namespace zmq
unsigned char tmpbuf [8]; unsigned char tmpbuf [8];
::zmq_msg_t in_progress; ::zmq_msg_t in_progress;
int64_t maxmsgsize;
decoder_t (const decoder_t&); decoder_t (const decoder_t&);
void operator = (const decoder_t&); void operator = (const decoder_t&);
}; };

View File

@ -39,6 +39,7 @@ zmq::options_t::options_t () :
reconnect_ivl (100), reconnect_ivl (100),
reconnect_ivl_max (0), reconnect_ivl_max (0),
backlog (100), backlog (100),
maxmsgsize (-1),
requires_in (false), requires_in (false),
requires_out (false), requires_out (false),
immediate_connect (true) immediate_connect (true)
@ -182,6 +183,14 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
backlog = *((int*) optval_); backlog = *((int*) optval_);
return 0; return 0;
case ZMQ_MAXMSGSIZE:
if (optvallen_ != sizeof (int64_t)) {
errno = EINVAL;
return -1;
}
maxmsgsize = *((int64_t*) optval_);
return 0;
} }
errno = EINVAL; errno = EINVAL;
@ -328,6 +337,15 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
*optvallen_ = sizeof (int); *optvallen_ = sizeof (int);
return 0; return 0;
case ZMQ_MAXMSGSIZE:
if (*optvallen_ < sizeof (int64_t)) {
errno = EINVAL;
return -1;
}
*((int64_t*) optval_) = maxmsgsize;
*optvallen_ = sizeof (int64_t);
return 0;
} }
errno = EINVAL; errno = EINVAL;

View File

@ -69,6 +69,9 @@ namespace zmq
// Maximum backlog for pending connections. // Maximum backlog for pending connections.
int backlog; int backlog;
// Maximal size of message to handle.
int64_t maxmsgsize;
// These options are never set by the user directly. Instead they are // These options are never set by the user directly. Instead they are
// provided by the specific socket type. // provided by the specific socket type.
bool requires_in; bool requires_in;

View File

@ -211,7 +211,8 @@ void zmq::pgm_receiver_t::in_event ()
it->second.joined = true; it->second.joined = true;
// Create and connect decoder for the peer. // Create and connect decoder for the peer.
it->second.decoder = new (std::nothrow) decoder_t (0); it->second.decoder = new (std::nothrow) decoder_t (0,
options.maxmsgsize);
alloc_assert (it->second.decoder); alloc_assert (it->second.decoder);
it->second.decoder->set_inout (inout); it->second.decoder->set_inout (inout);
} }

View File

@ -35,7 +35,7 @@
zmq::zmq_engine_t::zmq_engine_t (fd_t fd_, const options_t &options_) : zmq::zmq_engine_t::zmq_engine_t (fd_t fd_, const options_t &options_) :
inpos (NULL), inpos (NULL),
insize (0), insize (0),
decoder (in_batch_size), decoder (in_batch_size, options_.maxmsgsize),
outpos (NULL), outpos (NULL),
outsize (0), outsize (0),
encoder (out_batch_size), encoder (out_batch_size),