Browse Source

[Rework] Initial milter protocol support

tags/1.6.0
Vsevolod Stakhov 7 years ago
parent
commit
4d0e979529
4 changed files with 403 additions and 0 deletions
  1. 1
    0
      src/libserver/CMakeLists.txt
  2. 217
    0
      src/libserver/milter.c
  3. 118
    0
      src/libserver/milter.h
  4. 67
    0
      src/libserver/milter_internal.h

+ 1
- 0
src/libserver/CMakeLists.txt View File

@@ -10,6 +10,7 @@ SET(LIBRSPAMDSERVERSRC
${CMAKE_CURRENT_SOURCE_DIR}/fuzzy_backend.c
${CMAKE_CURRENT_SOURCE_DIR}/fuzzy_backend_sqlite.c
${CMAKE_CURRENT_SOURCE_DIR}/html.c
${CMAKE_CURRENT_SOURCE_DIR}/milter.c
${CMAKE_CURRENT_SOURCE_DIR}/monitored.c
${CMAKE_CURRENT_SOURCE_DIR}/protocol.c
${CMAKE_CURRENT_SOURCE_DIR}/re_cache.c

+ 217
- 0
src/libserver/milter.c View File

@@ -0,0 +1,217 @@
/*-
* Copyright 2017 Vsevolod Stakhov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "config.h"
#include "milter.h"
#include "milter_internal.h"
#include "email_addr.h"
#include "addr.h"
#include "unix-std.h"

static gboolean rspamd_milter_handle_session (
struct rspamd_milter_session *session,
struct rspamd_milter_private *priv);

static GQuark
rspamd_milter_quark (void)
{
return g_quark_from_static_string ("milter");
}

static void
rspamd_milter_io_handler (gint fd, gshort what, void *ud)
{
struct rspamd_milter_session *session = ud;
struct rspamd_milter_private *priv;

priv = session->priv;
}

static inline void
rspamd_milter_plan_io (struct rspamd_milter_session *session,
struct rspamd_milter_private *priv, gshort what)
{
if (event_get_base (&priv->ev)) {
event_del (&priv->ev);
}

event_set (&priv->ev, priv->fd, what, rspamd_milter_io_handler,
session);
event_base_set (priv->ev_base, &priv->ev);
event_add (&priv->ev, priv->ptv);
}

static gboolean
rspamd_milter_consume_input (struct rspamd_milter_session *session,
struct rspamd_milter_private *priv)
{
const guchar *p, *end;

p = priv->parser.buf->str + priv->parser.pos;
end = priv->parser.buf->str + priv->parser.buf->len;

while (p < end) {
switch (priv->parser.state) {
case st_read_cmd:
priv->parser.cur_cmd = *p;
priv->parser.state = st_len_1;
priv->parser.datalen = 0;
p++;
break;
case st_len_1:
/* The first length byte in big endian order */
priv->parser.datalen |= *p << 24;
priv->parser.state = st_len_2;
p++;
break;
case st_len_2:
/* The second length byte in big endian order */
priv->parser.datalen |= *p << 16;
priv->parser.state = st_len_3;
p++;
break;
case st_len_3:
/* The third length byte in big endian order */
priv->parser.datalen |= *p << 8;
priv->parser.state = st_len_4;
p++;
break;
case st_len_4:
/* The fourth length byte in big endian order */
priv->parser.datalen |= *p;
priv->parser.state = st_read_data;
p++;
break;
case st_read_data:
/* We might need some more data in buffer for further steps */
break;
}
}
}

static gboolean
rspamd_milter_handle_session (struct rspamd_milter_session *session,
struct rspamd_milter_private *priv)
{
gssize r;
GError *err;

g_assert (session != NULL);

switch (priv->state) {
case RSPAMD_MILTER_READ_MORE:
if (priv->parser.pos >= priv->parser.buf->allocated) {
priv->parser.buf = rspamd_fstring_grow (priv->parser.buf,
priv->parser.pos * 2);
}

r = read (priv->fd, priv->parser.buf->str + priv->parser.pos,
priv->parser.buf->allocated - priv->parser.pos);

if (r == -1) {
if (errno == EAGAIN || errno == EINTR) {
rspamd_milter_plan_io (session, priv, EV_READ);
}
else {
/* Fatal IO error */
err = g_error_new (rspamd_milter_quark (), errno,
"IO error: %s", strerror (errno));
REF_RETAIN (session);
priv->err_cb (priv->fd, session, priv->ud, err);
REF_RELEASE (session);
g_error_free (err);
}
}
else if (r == 0) {
err = g_error_new (rspamd_milter_quark (), ECONNRESET,
"Unexpected EOF");
REF_RETAIN (session);
priv->err_cb (priv->fd, session, priv->ud, err);
REF_RELEASE (session);
g_error_free (err);
}
else {
priv->parser.buf->len += r;

return rspamd_milter_consume_input (session, priv);
}
}
}


gboolean
rspamd_milter_handle_socket (gint fd, const struct timeval *tv,
struct event_base *ev_base, rspamd_milter_finish finish_cb,
rspamd_milter_error error_cb, void *ud)
{
struct rspamd_milter_session *session;
struct rspamd_milter_private *priv;

g_assert (finish_cb != NULL);
g_assert (error_cb != NULL);

session = g_malloc0 (sizeof (*session));
priv = g_malloc0 (sizeof (*priv));
priv->fd = fd;
priv->ud = ud;
priv->fin_cb = finish_cb;
priv->err_cb = error_cb;
priv->parser.state = st_read_cmd;
priv->parser.buf = rspamd_fstring_sized_new (100);
priv->ev_base = ev_base;
priv->state = RSPAMD_MILTER_READ_MORE;

if (tv) {
memcpy (&priv->tv, tv, sizeof (*tv));
priv->ptv = &priv->tv;
}
else {
priv->ptv = NULL;
}

session->priv = priv;

return rspamd_milter_handle_session (session, priv);
}

gboolean rspamd_milter_set_reply (struct rspamd_milter_session *session,
rspamd_fstring_t *xcode,
rspamd_fstring_t *rcode,
rspamd_fstring_t *reply);

gboolean rspamd_milter_send_action (gint fd,
struct rspamd_milter_session *session,
enum rspamd_milter_reply act);

gboolean rspamd_milter_add_header (struct rspamd_milter_session *session,
GString *name, GString *value);

gboolean rspamd_milter_del_header (struct rspamd_milter_session *session,
GString *name);

void
rspamd_milter_session_unref (struct rspamd_milter_session *session)
{
REF_RELEASE (session);
}

struct rspamd_milter_session *
rspamd_milter_session_ref (struct rspamd_milter_session *session)
{
REF_RETAIN (session);

return session;
}

+ 118
- 0
src/libserver/milter.h View File

@@ -0,0 +1,118 @@
/*-
* Copyright 2017 Vsevolod Stakhov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef RSPAMD_MILTER_H
#define RSPAMD_MILTER_H

#include "config.h"
#include "fstring.h"
#include "addr.h"
#include "ref.h"

enum rspamd_milter_reply {
RSPAMD_MILTER_ADDRCPT = '+',
RSPAMD_MILTER_DELRCPT = '-',
RSPAMD_MILTER_ACCEPT = 'a',
RSPAMD_MILTER_CONTINUE = 'c',
RSPAMD_MILTER_DISCARD = 'd',
RSPAMD_MILTER_ADDHEADER = 'h',
RSPAMD_MILTER_CHGHEADER = 'm',
RSPAMD_MILTER_REJECT = 'r',
RSPAMD_MILTER_TEMPFAIL = 't',
RSPAMD_MILTER_REPLYCODE = 'y'
};

struct rspamd_email_address;
struct event_base;

struct rspamd_milter_session {
GHashTable *macros;
rspamd_inet_addr_t *addr;
struct rspamd_email_address *from;
GPtrArray *rcpts;
rspamd_fstring_t *helo;
rspamd_fstring_t *hostname;
rspamd_fstring_t *message;
void *priv;
ref_entry_t ref;
};

typedef void (*rspamd_milter_finish) (gint fd,
struct rspamd_milter_session *session, void *ud);
typedef void (*rspamd_milter_error) (gint fd,
struct rspamd_milter_session *session,
void *ud, GError *err);

/**
* Handles socket with milter protocol
* @param fd
* @param finish_cb
* @param error_cb
* @param ud
* @return
*/
gboolean rspamd_milter_handle_socket (gint fd, const struct timeval *tv,
struct event_base *ev_base, rspamd_milter_finish finish_cb,
rspamd_milter_error error_cb, void *ud);

/**
* Sets SMTP reply string
* @param session
* @param xcode
* @param rcode
* @param reply
* @return
*/
gboolean rspamd_milter_set_reply (struct rspamd_milter_session *session,
rspamd_fstring_t *xcode,
rspamd_fstring_t *rcode,
rspamd_fstring_t *reply);

/**
* Send some action to the MTA
* @param fd
* @param session
* @param act
* @return
*/
gboolean rspamd_milter_send_action (gint fd,
struct rspamd_milter_session *session,
enum rspamd_milter_reply act);

/**
* Adds some header
* @param session
* @param name
* @param value
* @return
*/
gboolean rspamd_milter_add_header (struct rspamd_milter_session *session,
GString *name, GString *value);

/**
* Removes some header
* @param session
* @param name
* @return
*/
gboolean rspamd_milter_del_header (struct rspamd_milter_session *session,
GString *name);

void rspamd_milter_session_unref (struct rspamd_milter_session *session);

struct rspamd_milter_session * rspamd_milter_session_ref (
struct rspamd_milter_session *session);

#endif

+ 67
- 0
src/libserver/milter_internal.h View File

@@ -0,0 +1,67 @@
/*-
* Copyright 2017 Vsevolod Stakhov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef RSPAMD_MILTER_INTERNAL_H
#define RSPAMD_MILTER_INTERNAL_H

#include "config.h"
#include <event.h>

enum rspamd_milter_state {
st_read_cmd,
st_len_1,
st_len_2,
st_len_3,
st_len_4,
st_read_data
};

struct rspamd_milter_parser {
rspamd_fstring_t *buf;
goffset pos;
gsize datalen;
enum rspamd_milter_state state;
gchar cur_cmd;
};

struct rspamd_milter_outbuf {
rspamd_fstring_t *buf;
goffset pos;
struct rspamd_milter_outbuf *next, *prev;
};

enum rspamd_milter_io_state {
RSPAMD_MILTER_READ_MORE,
RSPAMD_MILTER_PROCESS_DATA,
RSPAMD_MILTER_WRITE_REPLY,
RSPAMD_MILTER_WANNA_DIE
};

struct rspamd_milter_private {
struct rspamd_milter_parser parser;
struct rspamd_milter_outbuf *out_chain;
struct event ev;
struct timeval tv;
struct timeval *ptv;
struct event_base *ev_base;
rspamd_milter_finish fin_cb;
rspamd_milter_error err_cb;
void *ud;
enum rspamd_milter_io_state state;
int fd;
};

#endif

Loading…
Cancel
Save