[syslog-ng] [PATCH] [logproto.c] "Invalid Frame Header" in syslog protocol

Balazs Scheidler bazsi at balabit.hu
Sun Jan 29 13:24:43 CET 2012


On Tue, 2012-01-24 at 18:10 +0100, Gergely Nagy wrote:
> When using the syslog protocol, in case when we received an EAGAIN
> during an attempt to send the framing, the frame was not resent,
> resulting in protocol errors and invalid frame header messages on the
> other end.
> 
> This patch corrects the problem by not using
> log_proto_text_client_post to send framed messages, but a wrapper that
> can resume sending the frame too.
> 
> Signed-off-by: Fried Zoltan <deirf at balabit.hu>
> Signed-off-by: Gergely Nagy <algernon at balabit.hu>
> ---
>  lib/logproto.c |   64 ++++++++++++++++++++++++++++++++++++-------------------
>  1 files changed, 42 insertions(+), 22 deletions(-)
> 
> diff --git a/lib/logproto.c b/lib/logproto.c
> index 16ca0d7..e2cf944 100644
> --- a/lib/logproto.c
> +++ b/lib/logproto.c
> @@ -35,6 +35,26 @@
>  #include <sys/uio.h>
>  #include <limits.h>
>  
> +
> +typedef struct _LogProtoTextClient
> +{
> +  LogProto super;
> +  guchar *partial;
> +  gsize partial_len, partial_pos;
> +} LogProtoTextClient;
> +
> +#define LPFCS_FRAME_INIT    0
> +#define LPFCS_FRAME_SEND    1
> +#define LPFCS_MESSAGE_SEND  2
> +
> +typedef struct _LogProtoFramedClient
> +{
> +  LogProtoTextClient super;
> +  gint state;
> +  gchar frame_hdr_buf[9];
> +  gint frame_hdr_len, frame_hdr_pos;
> +} LogProtoFramedClient;
> +
>  gboolean
>  log_proto_set_encoding(LogProto *self, const gchar *encoding)
>  {
> @@ -70,14 +90,6 @@ log_proto_free(LogProto *s)
>    g_free(s);
>  }
>  
> -
> -typedef struct _LogProtoTextClient
> -{
> -  LogProto super;
> -  guchar *partial;
> -  gsize partial_len, partial_pos;
> -} LogProtoTextClient;
> -
>  static gboolean
>  log_proto_text_client_prepare(LogProto *s, gint *fd, GIOCondition *cond)
>  {
> @@ -144,7 +156,7 @@ log_proto_text_client_flush(LogProto *s)
>   * successfully sent this message, or if it should be resent by the caller.
>   **/
>  static LogProtoStatus
> -log_proto_text_client_post(LogProto *s, guchar *msg, gsize msg_len, gboolean *consumed)
> +log_proto_client_post_writer(LogProto *s, guchar *msg, gsize msg_len, gboolean *consumed, gboolean syslog_proto)
>  {
>    LogProtoTextClient *self = (LogProtoTextClient *) s;
>    gint rc;
> @@ -173,6 +185,14 @@ log_proto_text_client_post(LogProto *s, guchar *msg, gsize msg_len, gboolean *co
>         */
>        return rc;
>      }
> +  else if (self->partial_len != 0 && !self->partial && syslog_proto)
> +  {
> +    LogProtoFramedClient *framed_self = (LogProtoFramedClient *) s;
> +    self->partial_pos =0;
> +    self->partial_len =0;
> +    framed_self->state = LPFCS_FRAME_INIT;
> +    return rc;
> +  }

sorry, but I won't commit this. you are casting "self" to a subclass in
a more generic class. I don't really see why this isn't handled by the
"if" in log_proto_framed_client_post() right after the call to
log_proto_text_client_post().

Here's the code that should do the same:

    case LPFCS_MESSAGE_SEND:
      rc = log_proto_text_client_post(s, msg, msg_len, consumed);
 
      /* NOTE: we don't check *consumed here, as we might have a pending
       * message in self->partial before we begin, in which case *consumed
       * will be FALSE. */
      
      if (rc == LPS_SUCCESS && self->super.partial == NULL)
        {
          self->state = LPFCS_FRAME_INIT;
        }
      return rc;

If a partial message is set and we get an EAGAIN, then log_proto_text_client_flush() 
returns LPS_SUCCESS and self->partial != NULL, which in turn leaves the state 
LPFCS_MESSAGE_SEND, causing the partial message to be resent.

What am I missing? can you describe the concrete scenario that triggers the bug?


Thanks.

-- 
Bazsi




More information about the syslog-ng mailing list