summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorGilles Chehade <gilles@cvs.openbsd.org>2018-11-03 13:42:25 +0000
committerGilles Chehade <gilles@cvs.openbsd.org>2018-11-03 13:42:25 +0000
commitc452475d031c4151fabfe3172dcfb16754a9f747 (patch)
tree7ff871d39f4c927f4524f55b2c17690e429c85b2 /usr.sbin
parent103e498ba78e6e90657cb40d45cc39ce9280e1b2 (diff)
bring plumbing for builtin filters
ok millert@, eric@, jung@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/smtpd/config.c6
-rw-r--r--usr.sbin/smtpd/lka.c14
-rw-r--r--usr.sbin/smtpd/lka_filter.c221
-rw-r--r--usr.sbin/smtpd/parse.y198
-rw-r--r--usr.sbin/smtpd/pony.c3
-rw-r--r--usr.sbin/smtpd/smtp.c3
-rw-r--r--usr.sbin/smtpd/smtp_session.c339
-rw-r--r--usr.sbin/smtpd/smtpd.h50
-rw-r--r--usr.sbin/smtpd/smtpd/Makefile3
9 files changed, 735 insertions, 102 deletions
diff --git a/usr.sbin/smtpd/config.c b/usr.sbin/smtpd/config.c
index 8882732b7ea..00da2891252 100644
--- a/usr.sbin/smtpd/config.c
+++ b/usr.sbin/smtpd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.44 2018/11/01 14:48:49 gilles Exp $ */
+/* $OpenBSD: config.c,v 1.45 2018/11/03 13:42:24 gilles Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -48,6 +48,7 @@ config_default(void)
struct mta_limits *limits = NULL;
struct table *t = NULL;
char hostname[HOST_NAME_MAX+1];
+ uint8_t i;
if (getmailname(hostname, sizeof hostname) == -1)
return NULL;
@@ -125,6 +126,9 @@ config_default(void)
TAILQ_INIT(conf->sc_listeners);
TAILQ_INIT(conf->sc_rules);
+ for (i = 0; i < nitems(conf->sc_filter_rules); ++i)
+ TAILQ_INIT(&conf->sc_filter_rules[i]);
+
/* bounce dispatcher */
conf->sc_dispatcher_bounce->type = DISPATCHER_BOUNCE;
diff --git a/usr.sbin/smtpd/lka.c b/usr.sbin/smtpd/lka.c
index ac6713b7084..f38cb786536 100644
--- a/usr.sbin/smtpd/lka.c
+++ b/usr.sbin/smtpd/lka.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lka.c,v 1.211 2018/11/02 17:20:22 gilles Exp $ */
+/* $OpenBSD: lka.c,v 1.212 2018/11/03 13:42:24 gilles Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -87,6 +87,8 @@ lka_imsg(struct mproc *p, struct imsg *imsg)
const char *command, *response;
const char *ciphers;
struct sockaddr_storage ss_src, ss_dest;
+ int filter_phase;
+ const char *filter_param;
if (imsg == NULL)
lka_shutdown();
@@ -481,6 +483,16 @@ lka_imsg(struct mproc *p, struct imsg *imsg)
lka_report_smtp_protocol_server(tm, reqid, response);
return;
+
+ case IMSG_SMTP_FILTER:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_int(&m, &filter_phase);
+ m_get_string(&m, &filter_param);
+ m_end(&m);
+
+ lka_filter(reqid, filter_phase, filter_param);
+ return;
}
errx(1, "lka_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
diff --git a/usr.sbin/smtpd/lka_filter.c b/usr.sbin/smtpd/lka_filter.c
new file mode 100644
index 00000000000..7bbdddd0167
--- /dev/null
+++ b/usr.sbin/smtpd/lka_filter.c
@@ -0,0 +1,221 @@
+/* $OpenBSD: lka_filter.c,v 1.1 2018/11/03 13:42:24 gilles Exp $ */
+
+/*
+ * Copyright (c) 2018 Gilles Chehade <gilles@poolp.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/tree.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <event.h>
+#include <imsg.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "smtpd.h"
+#include "log.h"
+
+static void filter_proceed(uint64_t, enum filter_phase, const char *);
+static void filter_rewrite(uint64_t, enum filter_phase, const char *);
+static void filter_reject(uint64_t, enum filter_phase, const char *);
+static void filter_disconnect(uint64_t, enum filter_phase, const char *);
+
+static int filter_exec_notimpl(uint64_t, struct filter_rule *, const char *);
+static int filter_exec_connected(uint64_t, struct filter_rule *, const char *);
+static int filter_exec_helo(uint64_t, struct filter_rule *, const char *);
+static int filter_exec_mail_from(uint64_t, struct filter_rule *, const char *);
+static int filter_exec_rcpt_to(uint64_t, struct filter_rule *, const char *);
+
+
+static struct filter_exec {
+ enum filter_phase phase;
+ const char *phase_name;
+ int (*func)(uint64_t, struct filter_rule *, const char *);
+} filter_execs[] = {
+ { FILTER_AUTH, "auth", filter_exec_notimpl },
+ { FILTER_CONNECTED, "connected", filter_exec_connected },
+ { FILTER_DATA, "data", filter_exec_notimpl },
+ { FILTER_EHLO, "ehlo", filter_exec_helo },
+ { FILTER_HELO, "helo", filter_exec_helo },
+ { FILTER_STARTTLS, "starttls", filter_exec_notimpl },
+ { FILTER_MAIL_FROM, "mail-from", filter_exec_mail_from },
+ { FILTER_NOOP, "noop", filter_exec_notimpl },
+ { FILTER_QUIT, "quit", filter_exec_notimpl },
+ { FILTER_RCPT_TO, "rcpt-to", filter_exec_rcpt_to },
+ { FILTER_RSET, "rset", filter_exec_notimpl },
+};
+
+void
+lka_filter(uint64_t reqid, enum filter_phase phase, const char *param)
+{
+ struct filter_rule *rule;
+ uint8_t i;
+
+ for (i = 0; i < nitems(filter_execs); ++i)
+ if (phase == filter_execs[i].phase)
+ break;
+ if (i == nitems(filter_execs))
+ goto proceed;
+
+ TAILQ_FOREACH(rule, &env->sc_filter_rules[phase], entry) {
+ if (! filter_execs[i].func(reqid, rule, param)) {
+ if (rule->rewrite)
+ filter_rewrite(reqid, phase, rule->rewrite);
+ else if (rule->disconnect)
+ filter_disconnect(reqid, phase, rule->disconnect);
+ else
+ filter_reject(reqid, phase, rule->reject);
+ return;
+ }
+ }
+
+proceed:
+ filter_proceed(reqid, phase, param);
+}
+
+static void
+filter_proceed(uint64_t reqid, enum filter_phase phase, const char *param)
+{
+ m_create(p_pony, IMSG_SMTP_FILTER, 0, 0, -1);
+ m_add_id(p_pony, reqid);
+ m_add_int(p_pony, phase);
+ m_add_int(p_pony, FILTER_PROCEED);
+ m_add_string(p_pony, param);
+ m_close(p_pony);
+}
+
+static void
+filter_rewrite(uint64_t reqid, enum filter_phase phase, const char *param)
+{
+ m_create(p_pony, IMSG_SMTP_FILTER, 0, 0, -1);
+ m_add_id(p_pony, reqid);
+ m_add_int(p_pony, phase);
+ m_add_int(p_pony, FILTER_REWRITE);
+ m_add_string(p_pony, param);
+ m_close(p_pony);
+}
+
+static void
+filter_reject(uint64_t reqid, enum filter_phase phase, const char *message)
+{
+ m_create(p_pony, IMSG_SMTP_FILTER, 0, 0, -1);
+ m_add_id(p_pony, reqid);
+ m_add_int(p_pony, phase);
+ m_add_int(p_pony, FILTER_REJECT);
+ m_add_string(p_pony, message);
+ m_close(p_pony);
+}
+
+static void
+filter_disconnect(uint64_t reqid, enum filter_phase phase, const char *message)
+{
+ m_create(p_pony, IMSG_SMTP_FILTER, 0, 0, -1);
+ m_add_id(p_pony, reqid);
+ m_add_int(p_pony, phase);
+ m_add_int(p_pony, FILTER_DISCONNECT);
+ m_add_string(p_pony, message);
+ m_close(p_pony);
+}
+
+
+/* below is code for builtin filters */
+
+static int
+filter_check_table(struct filter_rule *rule, enum table_service kind, const char *key)
+{
+ int ret = 0;
+
+ if (rule->table) {
+ if (table_lookup(rule->table, NULL, key, kind, NULL) > 0)
+ ret = 1;
+ ret = rule->not_table < 0 ? !ret : ret;
+ }
+ return ret;
+}
+
+static int
+filter_check_regex(struct filter_rule *rule, const char *key)
+{
+ int ret = 0;
+
+ if (rule->regex) {
+ if (table_lookup(rule->regex, NULL, key, K_REGEX, NULL) > 0)
+ ret = 1;
+ ret = rule->not_regex < 0 ? !ret : ret;
+ }
+ return ret;
+}
+
+static int
+filter_exec_notimpl(uint64_t reqid, struct filter_rule *rule, const char *param)
+{
+ return 1;
+}
+
+static int
+filter_exec_connected(uint64_t reqid, struct filter_rule *rule, const char *param)
+{
+ if (filter_check_table(rule, K_NETADDR, param) ||
+ filter_check_regex(rule, param))
+ return 0;
+ return 1;
+}
+
+static int
+filter_exec_helo(uint64_t reqid, struct filter_rule *rule, const char *param)
+{
+ if (filter_check_table(rule, K_DOMAIN, param) ||
+ filter_check_regex(rule, param))
+ return 0;
+ return 1;
+}
+
+static int
+filter_exec_mail_from(uint64_t reqid, struct filter_rule *rule, const char *param)
+{
+ char buffer[SMTPD_MAXMAILADDRSIZE];
+
+ (void)strlcpy(buffer, param+1, sizeof(buffer));
+ buffer[strcspn(buffer, ">")] = '\0';
+ param = buffer;
+
+ if (filter_check_table(rule, K_MAILADDR, param) ||
+ filter_check_regex(rule, param))
+ return 0;
+ return 1;
+}
+
+static int
+filter_exec_rcpt_to(uint64_t reqid, struct filter_rule *rule, const char *param)
+{
+ char buffer[SMTPD_MAXMAILADDRSIZE];
+
+ (void)strlcpy(buffer, param+1, sizeof(buffer));
+ buffer[strcspn(buffer, ">")] = '\0';
+ param = buffer;
+
+ if (filter_check_table(rule, K_MAILADDR, param) ||
+ filter_check_regex(rule, param))
+ return 0;
+ return 1;
+}
diff --git a/usr.sbin/smtpd/parse.y b/usr.sbin/smtpd/parse.y
index 7f6b7ffde4f..e5b4a8c2582 100644
--- a/usr.sbin/smtpd/parse.y
+++ b/usr.sbin/smtpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.225 2018/11/01 14:48:49 gilles Exp $ */
+/* $OpenBSD: parse.y,v 1.226 2018/11/03 13:42:24 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -106,6 +106,7 @@ static struct ca *sca;
struct dispatcher *dispatcher;
struct rule *rule;
struct processor *processor;
+struct filter_rule *filter_rule;
enum listen_options {
LO_FAMILY = 0x000001,
@@ -173,9 +174,10 @@ typedef struct {
%token ACTION ALIAS ANY ARROW AUTH AUTH_OPTIONAL
%token BACKUP BOUNCE
-%token CA CERT CHROOT CIPHERS COMPRESSION
-%token DHE DOMAIN
-%token ENCRYPTION ERROR EXPAND_ONLY
+%token CA CERT CHROOT CIPHERS COMPRESSION CONNECT
+%token CHECK_REGEX CHECK_TABLE
+%token DATA DHE DISCONNECT DOMAIN
+%token EHLO ENABLE ENCRYPTION ERROR EXPAND_ONLY
%token FILTER FOR FORWARD_ONLY FROM
%token GROUP
%token HELO HELO_SRC HOST HOSTNAME HOSTNAMES
@@ -184,11 +186,11 @@ typedef struct {
%token KEY
%token LIMIT LISTEN LMTP LOCAL
%token MAIL_FROM MAILDIR MASK_SRC MASQUERADE MATCH MAX_MESSAGE_SIZE MAX_DEFERRED MBOX MDA MTA MX
-%token NO_DSN NO_VERIFY
+%token NO_DSN NO_VERIFY NOOP
%token ON
%token PKI PORT PROC
-%token QUEUE
-%token RCPT_TO RECIPIENT RECEIVEDAUTH RELAY REJECT REPORT
+%token QUEUE QUIT
+%token RCPT_TO RECIPIENT RECEIVEDAUTH RELAY REJECT REPORT REWRITE RSET
%token SCHEDULER SENDER SENDERS SMTP SMTPS SOCKET SRC SUB_ADDR_DELIM
%token TABLE TAG TAGGED TLS TLS_REQUIRE TTL
%token USER USERBASE
@@ -220,6 +222,7 @@ grammar : /* empty */
| grammar table '\n'
| grammar dispatcher '\n'
| grammar match '\n'
+ | grammar filter '\n'
| grammar error '\n' { file->errors++; }
;
@@ -447,6 +450,7 @@ PROC STRING STRING {
}
;
+
proc_params_opt:
USER STRING {
if (processor->user) {
@@ -1129,6 +1133,176 @@ MATCH {
}
;
+/*
+filter_action_proc:
+ON STRING {
+ filter_rule->filter = $2;
+}
+;
+*/
+
+filter_action_builtin:
+REJECT STRING {
+ filter_rule->reject = $2;
+}
+| DISCONNECT STRING {
+ filter_rule->disconnect = $2;
+}
+/*
+| REWRITE STRING {
+ filter_rule->rewrite = $2;
+}
+*/
+;
+
+filter_phase_check_table:
+negation CHECK_TABLE tables {
+ filter_rule->not_table = $1 ? -1 : 1;
+ filter_rule->table = $3;
+}
+;
+
+filter_phase_check_regex:
+negation CHECK_REGEX tables {
+ filter_rule->not_regex = $1 ? -1 : 1;
+ filter_rule->regex = $3;
+}
+;
+
+filter_phase_connect_options:
+filter_phase_check_table | filter_phase_check_regex;
+
+filter_phase_connect:
+CONNECT {
+ filter_rule->phase = FILTER_CONNECTED;
+} filter_phase_connect_options filter_action_builtin
+ /*
+| CONNECT {
+ filter_rule->phase = FILTER_CONNECTED;
+} filter_action_proc
+ */
+;
+
+filter_phase_helo_options:
+filter_phase_check_table | filter_phase_check_regex;
+
+filter_phase_helo:
+HELO {
+ filter_rule->phase = FILTER_HELO;
+} filter_phase_helo_options filter_action_builtin
+ /*
+| HELO {
+ filter_rule->phase = FILTER_HELO;
+} filter_action_proc
+ */
+;
+
+filter_phase_ehlo:
+EHLO {
+ filter_rule->phase = FILTER_EHLO;
+} filter_phase_helo_options filter_action_builtin
+ /*
+| EHLO {
+ filter_rule->phase = FILTER_EHLO;
+} filter_action_proc
+ */
+;
+
+filter_phase_mail_from_options:
+filter_phase_check_table | filter_phase_check_regex;
+
+filter_phase_mail_from:
+MAIL_FROM {
+ filter_rule->phase = FILTER_MAIL_FROM;
+} filter_phase_mail_from_options filter_action_builtin
+ /*
+| MAIL_FROM {
+ filter_rule->phase = FILTER_MAIL_FROM;
+} filter_action_proc
+ */
+;
+
+filter_phase_rcpt_to_options:
+filter_phase_check_table | filter_phase_check_regex;
+
+filter_phase_rcpt_to:
+RCPT_TO {
+ filter_rule->phase = FILTER_RCPT_TO;
+} filter_phase_rcpt_to_options filter_action_builtin
+ /*
+| RCPT_TO {
+ filter_rule->phase = FILTER_RCPT_TO;
+} filter_action_proc
+ */
+;
+
+filter_phase_data:
+DATA {
+ filter_rule->phase = FILTER_DATA;
+} filter_action_builtin
+ /*
+| DATA {
+ filter_rule->phase = FILTER_DATA;
+} filter_action_proc
+ */
+;
+
+filter_phase_quit:
+QUIT {
+ filter_rule->phase = FILTER_QUIT;
+} filter_action_builtin
+ /*
+| QUIT {
+ filter_rule->phase = FILTER_QUIT;
+} filter_action_proc
+ */
+;
+
+filter_phase_rset:
+RSET {
+ filter_rule->phase = FILTER_RSET;
+} filter_action_builtin
+ /*
+| RSET {
+ filter_rule->phase = FILTER_RSET;
+} filter_action_proc
+ */
+;
+
+filter_phase_noop:
+NOOP {
+ filter_rule->phase = FILTER_NOOP;
+} filter_action_builtin
+ /*
+| NOOP {
+ filter_rule->phase = FILTER_NOOP;
+} filter_action_proc
+ */
+;
+
+
+
+filter_phase:
+filter_phase_connect
+| filter_phase_helo
+| filter_phase_ehlo
+| filter_phase_mail_from
+| filter_phase_rcpt_to
+| filter_phase_data
+| filter_phase_quit
+| filter_phase_noop
+| filter_phase_rset
+;
+
+filter:
+FILTER SMTP {
+ filter_rule = xcalloc(1, sizeof *filter_rule);
+} filter_phase {
+ TAILQ_INSERT_TAIL(&conf->sc_filter_rules[filter_rule->phase], filter_rule, entry);
+ filter_rule = NULL;
+}
+;
+
size : NUMBER {
if ($1 < 0) {
yyerror("invalid size: %" PRId64, $1);
@@ -1676,11 +1850,17 @@ lookup(char *s)
{ "bounce", BOUNCE },
{ "ca", CA },
{ "cert", CERT },
+ { "check-regex", CHECK_REGEX },
+ { "check-table", CHECK_TABLE },
{ "chroot", CHROOT },
{ "ciphers", CIPHERS },
{ "compression", COMPRESSION },
+ { "connect", CONNECT },
+ { "data", DATA },
{ "dhe", DHE },
+ { "disconnect", DISCONNECT },
{ "domain", DOMAIN },
+ { "ehlo", EHLO },
{ "encryption", ENCRYPTION },
{ "expand-only", EXPAND_ONLY },
{ "filter", FILTER },
@@ -1715,17 +1895,21 @@ lookup(char *s)
{ "mx", MX },
{ "no-dsn", NO_DSN },
{ "no-verify", NO_VERIFY },
+ { "noop", NOOP },
{ "on", ON },
{ "pki", PKI },
{ "port", PORT },
{ "proc", PROC },
{ "queue", QUEUE },
+ { "quit", QUIT },
{ "rcpt-to", RCPT_TO },
{ "received-auth", RECEIVEDAUTH },
{ "recipient", RECIPIENT },
{ "reject", REJECT },
{ "relay", RELAY },
{ "report", REPORT },
+ { "rewrite", REWRITE },
+ { "rset", RSET },
{ "scheduler", SCHEDULER },
{ "senders", SENDERS },
{ "smtp", SMTP },
diff --git a/usr.sbin/smtpd/pony.c b/usr.sbin/smtpd/pony.c
index 7af7f014789..411fbfa6dca 100644
--- a/usr.sbin/smtpd/pony.c
+++ b/usr.sbin/smtpd/pony.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pony.c,v 1.21 2018/07/25 16:00:48 eric Exp $ */
+/* $OpenBSD: pony.c,v 1.22 2018/11/03 13:42:24 gilles Exp $ */
/*
* Copyright (c) 2014 Gilles Chehade <gilles@poolp.org>
@@ -91,6 +91,7 @@ pony_imsg(struct mproc *p, struct imsg *imsg)
case IMSG_SMTP_MESSAGE_COMMIT:
case IMSG_SMTP_MESSAGE_CREATE:
case IMSG_SMTP_MESSAGE_OPEN:
+ case IMSG_SMTP_FILTER:
case IMSG_QUEUE_ENVELOPE_SUBMIT:
case IMSG_QUEUE_ENVELOPE_COMMIT:
case IMSG_QUEUE_SMTP_SESSION:
diff --git a/usr.sbin/smtpd/smtp.c b/usr.sbin/smtpd/smtp.c
index 80fc099b672..4eab35df03d 100644
--- a/usr.sbin/smtpd/smtp.c
+++ b/usr.sbin/smtpd/smtp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtp.c,v 1.159 2018/07/25 16:00:48 eric Exp $ */
+/* $OpenBSD: smtp.c,v 1.160 2018/11/03 13:42:24 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -68,6 +68,7 @@ smtp_imsg(struct mproc *p, struct imsg *imsg)
case IMSG_SMTP_AUTHENTICATE:
case IMSG_SMTP_TLS_INIT:
case IMSG_SMTP_TLS_VERIFY:
+ case IMSG_SMTP_FILTER:
smtp_session_imsg(p, imsg);
return;
diff --git a/usr.sbin/smtpd/smtp_session.c b/usr.sbin/smtpd/smtp_session.c
index 155b5dbe1d1..1c165e09aad 100644
--- a/usr.sbin/smtpd/smtp_session.c
+++ b/usr.sbin/smtpd/smtp_session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtp_session.c,v 1.345 2018/11/02 17:20:22 gilles Exp $ */
+/* $OpenBSD: smtp_session.c,v 1.346 2018/11/03 13:42:24 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -191,40 +191,53 @@ static void smtp_message_fd(struct smtp_tx *, int);
static void smtp_message_end(struct smtp_tx *);
static int smtp_message_printf(struct smtp_tx *, const char *, ...);
-static int smtp_check_rset(struct smtp_session *);
-static int smtp_check_helo(struct smtp_session *, int, const char *);
+static int smtp_check_rset(struct smtp_session *, const char *);
+static int smtp_check_helo(struct smtp_session *, const char *);
+static int smtp_check_ehlo(struct smtp_session *, const char *);
static int smtp_check_auth(struct smtp_session *s, const char *);
static int smtp_check_starttls(struct smtp_session *, const char *);
-static int smtp_check_mail_from(struct smtp_session *);
-static int smtp_check_rcpt_to(struct smtp_session *);
-static int smtp_check_data(struct smtp_session *);
-
-static void smtp_proceed_rset(struct smtp_session *);
-static void smtp_proceed_helo(struct smtp_session *, int, char *);
-static void smtp_proceed_auth(struct smtp_session *, char *);
-static void smtp_proceed_starttls(struct smtp_session *);
-static void smtp_proceed_mail_from(struct smtp_session *, char *);
-static void smtp_proceed_rcpt_to(struct smtp_session *, char *);
-static void smtp_proceed_data(struct smtp_session *);
-static void smtp_proceed_noop(struct smtp_session *);
-static void smtp_proceed_help(struct smtp_session *);
-static void smtp_proceed_wiz(struct smtp_session *);
-static void smtp_proceed_quit(struct smtp_session *);
-
-static struct { int code; const char *cmd; } commands[] = {
- { CMD_HELO, "HELO" },
- { CMD_EHLO, "EHLO" },
- { CMD_STARTTLS, "STARTTLS" },
- { CMD_AUTH, "AUTH" },
- { CMD_MAIL_FROM, "MAIL FROM" },
- { CMD_RCPT_TO, "RCPT TO" },
- { CMD_DATA, "DATA" },
- { CMD_RSET, "RSET" },
- { CMD_QUIT, "QUIT" },
- { CMD_HELP, "HELP" },
- { CMD_WIZ, "WIZ" },
- { CMD_NOOP, "NOOP" },
- { -1, NULL },
+static int smtp_check_mail_from(struct smtp_session *, const char *);
+static int smtp_check_rcpt_to(struct smtp_session *, const char *);
+static int smtp_check_data(struct smtp_session *, const char *);
+static int smtp_check_noparam(struct smtp_session *, const char *);
+
+static void smtp_filter_phase(enum filter_phase, struct smtp_session *, const char *);
+
+static void smtp_proceed_connected(struct smtp_session *);
+static void smtp_proceed_rset(struct smtp_session *, const char *);
+static void smtp_proceed_helo(struct smtp_session *, const char *);
+static void smtp_proceed_ehlo(struct smtp_session *, const char *);
+static void smtp_proceed_auth(struct smtp_session *, const char *);
+static void smtp_proceed_starttls(struct smtp_session *, const char *);
+static void smtp_proceed_mail_from(struct smtp_session *, const char *);
+static void smtp_proceed_rcpt_to(struct smtp_session *, const char *);
+static void smtp_proceed_data(struct smtp_session *, const char *);
+static void smtp_proceed_noop(struct smtp_session *, const char *);
+static void smtp_proceed_help(struct smtp_session *, const char *);
+static void smtp_proceed_wiz(struct smtp_session *, const char *);
+static void smtp_proceed_quit(struct smtp_session *, const char *);
+
+static struct {
+ int code;
+ enum filter_phase filter_phase;
+ const char *cmd;
+
+ int (*check)(struct smtp_session *, const char *);
+ void (*proceed)(struct smtp_session *, const char *);
+} commands[] = {
+ { CMD_HELO, FILTER_HELO, "HELO", smtp_check_helo, smtp_proceed_helo },
+ { CMD_EHLO, FILTER_EHLO, "EHLO", smtp_check_ehlo, smtp_proceed_ehlo },
+ { CMD_STARTTLS, FILTER_STARTTLS, "STARTTLS", smtp_check_starttls, smtp_proceed_starttls },
+ { CMD_AUTH, FILTER_AUTH, "AUTH", smtp_check_auth, smtp_proceed_auth },
+ { CMD_MAIL_FROM, FILTER_MAIL_FROM, "MAIL FROM", smtp_check_mail_from, smtp_proceed_mail_from },
+ { CMD_RCPT_TO, FILTER_RCPT_TO, "RCPT TO", smtp_check_rcpt_to, smtp_proceed_rcpt_to },
+ { CMD_DATA, FILTER_DATA, "DATA", smtp_check_data, smtp_proceed_data },
+ { CMD_RSET, FILTER_RSET, "RSET", smtp_check_rset, smtp_proceed_rset },
+ { CMD_QUIT, FILTER_QUIT, "QUIT", smtp_check_noparam, smtp_proceed_quit },
+ { CMD_NOOP, FILTER_NOOP, "NOOP", smtp_check_noparam, smtp_proceed_noop },
+ { CMD_HELP, FILTER_HELP, "HELP", smtp_check_noparam, smtp_proceed_help },
+ { CMD_WIZ, FILTER_WIZ, "WIZ", smtp_check_noparam, smtp_proceed_wiz },
+ { -1, 0, NULL, NULL },
};
static struct tree wait_lka_helo;
@@ -236,6 +249,7 @@ static struct tree wait_queue_fd;
static struct tree wait_queue_commit;
static struct tree wait_ssl_init;
static struct tree wait_ssl_verify;
+static struct tree wait_filters;
static void
header_append_domain_buffer(char *buffer, char *domain, size_t len)
@@ -516,6 +530,7 @@ smtp_session_init(void)
tree_init(&wait_queue_commit);
tree_init(&wait_ssl_init);
tree_init(&wait_ssl_verify);
+ tree_init(&wait_filters);
init = 1;
}
}
@@ -601,6 +616,10 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg)
uint32_t msgid;
int status, success;
void *ssl_ctx;
+ enum filter_phase filter_phase;
+ int filter_response;
+ const char *filter_param;
+ uint8_t i;
switch (imsg->hdr.type) {
@@ -864,6 +883,49 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg)
smtp_tls_verified(s);
io_resume(s->io, IO_IN);
return;
+
+ case IMSG_SMTP_FILTER:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_int(&m, (int *)&filter_phase);
+ m_get_int(&m, &filter_response);
+ m_get_string(&m, &filter_param);
+ m_end(&m);
+
+ s = tree_xpop(&wait_filters, reqid);
+
+ switch (filter_response) {
+ case FILTER_REJECT:
+ case FILTER_DISCONNECT:
+ if (!valid_smtp_response(filter_param) ||
+ (filter_param[0] != '4' && filter_param[0] != '5'))
+ filter_param = "421 Internal server error";
+ if (!strncmp(filter_param, "421", 3))
+ filter_response = FILTER_DISCONNECT;
+
+ smtp_reply(s, "%s", filter_param);
+
+ if (filter_response == FILTER_DISCONNECT)
+ smtp_enter_state(s, STATE_QUIT);
+ break;
+
+ case FILTER_PROCEED:
+ case FILTER_REWRITE:
+ if (filter_phase == FILTER_CONNECTED) {
+ smtp_proceed_connected(s);
+ return;
+ }
+ for (i = 0; i < nitems(commands); ++i)
+ if (commands[i].filter_phase == filter_phase) {
+ if (filter_response == FILTER_REWRITE)
+ if (!commands[i].check(s, filter_param))
+ break;
+ commands[i].proceed(s, filter_param);
+ break;
+ }
+ break;
+ }
+ return;
}
log_warnx("smtp_session_imsg: unexpected %s imsg",
@@ -1082,70 +1144,77 @@ smtp_command(struct smtp_session *s, char *line)
* INIT
*/
case CMD_HELO:
+ if (!smtp_check_helo(s, args))
+ break;
+ smtp_filter_phase(FILTER_HELO, s, args);
+ break;
+
case CMD_EHLO:
- if (!smtp_check_helo(s, cmd, args))
+ if (!smtp_check_ehlo(s, args))
break;
- smtp_proceed_helo(s, cmd, args);
+ smtp_filter_phase(FILTER_EHLO, s, args);
break;
+
/*
* SETUP
*/
case CMD_STARTTLS:
if (!smtp_check_starttls(s, args))
break;
- smtp_proceed_starttls(s);
+
+ smtp_filter_phase(FILTER_STARTTLS, s, NULL);
break;
case CMD_AUTH:
if (!smtp_check_auth(s, args))
break;
- smtp_proceed_auth(s, args);
+ smtp_filter_phase(FILTER_AUTH, s, NULL);
break;
case CMD_MAIL_FROM:
- if (!smtp_check_mail_from(s))
+ if (!smtp_check_mail_from(s, args))
break;
- smtp_proceed_mail_from(s, args);
+ smtp_filter_phase(FILTER_MAIL_FROM, s, args);
break;
/*
* TRANSACTION
*/
case CMD_RCPT_TO:
- if (!smtp_check_rcpt_to(s))
+ if (!smtp_check_rcpt_to(s, args))
break;
- smtp_proceed_rcpt_to(s, args);
+ smtp_filter_phase(FILTER_RCPT_TO, s, args);
break;
case CMD_RSET:
- if (!smtp_check_rset(s))
+ if (!smtp_check_rset(s, args))
break;
- smtp_proceed_rset(s);
+ smtp_filter_phase(FILTER_RSET, s, NULL);
break;
case CMD_DATA:
- if (!smtp_check_data(s))
+ if (!smtp_check_data(s, args))
break;
- smtp_proceed_data(s);
+ smtp_filter_phase(FILTER_DATA, s, NULL);
break;
/*
* ANY
*/
case CMD_QUIT:
- smtp_proceed_quit(s);
+ smtp_filter_phase(FILTER_QUIT, s, NULL);
break;
case CMD_NOOP:
- smtp_proceed_noop(s);
+ smtp_filter_phase(FILTER_NOOP, s, NULL);
break;
case CMD_HELP:
- smtp_proceed_help(s);
+ smtp_proceed_help(s, NULL);
break;
case CMD_WIZ:
- smtp_proceed_wiz(s);
+ smtp_proceed_wiz(s, NULL);
break;
default:
@@ -1157,7 +1226,7 @@ smtp_command(struct smtp_session *s, char *line)
}
static int
-smtp_check_rset(struct smtp_session *s)
+smtp_check_rset(struct smtp_session *s, const char *args)
{
if (s->helo[0] == '\0') {
smtp_reply(s, "503 %s %s: Command not allowed at this point.",
@@ -1169,8 +1238,15 @@ smtp_check_rset(struct smtp_session *s)
}
static int
-smtp_check_helo(struct smtp_session *s, int cmd, const char *args)
+smtp_check_helo(struct smtp_session *s, const char *args)
{
+ if (!s->banner_sent) {
+ smtp_reply(s, "503 %s %s: Command not allowed at this point.",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
+ return 0;
+ }
+
if (s->helo[0]) {
smtp_reply(s, "503 %s %s: Already identified",
esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
@@ -1179,10 +1255,43 @@ smtp_check_helo(struct smtp_session *s, int cmd, const char *args)
}
if (args == NULL) {
- smtp_reply(s, "501 %s %s: %s requires domain name",
+ smtp_reply(s, "501 %s %s: HELO requires domain name",
esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
- esc_description(ESC_INVALID_COMMAND),
- (cmd == CMD_HELO) ? "HELO" : "EHLO");
+ esc_description(ESC_INVALID_COMMAND));
+ return 0;
+ }
+
+ if (!valid_domainpart(args)) {
+ smtp_reply(s, "501 %s %s: Invalid domain name",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
+ esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+smtp_check_ehlo(struct smtp_session *s, const char *args)
+{
+ if (!s->banner_sent) {
+ smtp_reply(s, "503 %s %s: Command not allowed at this point.",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
+ return 0;
+ }
+
+ if (s->helo[0]) {
+ smtp_reply(s, "503 %s %s: Already identified",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
+ return 0;
+ }
+
+ if (args == NULL) {
+ smtp_reply(s, "501 %s %s: EHLO requires domain name",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
return 0;
}
@@ -1265,7 +1374,7 @@ smtp_check_starttls(struct smtp_session *s, const char *args)
}
static int
-smtp_check_mail_from(struct smtp_session *s)
+smtp_check_mail_from(struct smtp_session *s, const char *args)
{
if (s->helo[0] == '\0' || s->tx) {
smtp_reply(s, "503 %s %s: Command not allowed at this point.",
@@ -1311,7 +1420,7 @@ smtp_check_mail_from(struct smtp_session *s)
}
static int
-smtp_check_rcpt_to(struct smtp_session *s)
+smtp_check_rcpt_to(struct smtp_session *s, const char *args)
{
if (s->tx == NULL) {
smtp_reply(s, "503 %s %s: Command not allowed at this point.",
@@ -1324,7 +1433,7 @@ smtp_check_rcpt_to(struct smtp_session *s)
}
static int
-smtp_check_data(struct smtp_session *s)
+smtp_check_data(struct smtp_session *s, const char *args)
{
if (s->tx == NULL) {
smtp_reply(s, "503 %s %s: Command not allowed at this point.",
@@ -1343,9 +1452,44 @@ smtp_check_data(struct smtp_session *s)
return 1;
}
+static int
+smtp_check_noparam(struct smtp_session *s, const char *args)
+{
+ return 1;
+}
static void
-smtp_proceed_rset(struct smtp_session *s)
+smtp_query_filters(enum filter_phase phase, struct smtp_session *s, const char *args)
+{
+ uint8_t i;
+
+ if (TAILQ_FIRST(&env->sc_filter_rules[phase])) {
+ m_create(p_lka, IMSG_SMTP_FILTER, 0, 0, -1);
+ m_add_id(p_lka, s->id);
+ m_add_int(p_lka, phase);
+ m_add_string(p_lka, args);
+ m_close(p_lka);
+ tree_xset(&wait_filters, s->id, s);
+ return;
+ }
+
+ if (phase == FILTER_CONNECTED) {
+ smtp_proceed_connected(s);
+ return;
+ }
+ for (i = 0; i < nitems(commands); ++i)
+ if (commands[i].filter_phase == phase)
+ commands[i].proceed(s, args);
+}
+
+static void
+smtp_filter_phase(enum filter_phase phase, struct smtp_session *s, const char *param)
+{
+ smtp_query_filters(phase, s, param ? param : "");
+}
+
+static void
+smtp_proceed_rset(struct smtp_session *s, const char *args)
{
if (s->tx) {
if (s->tx->msgid)
@@ -1358,45 +1502,56 @@ smtp_proceed_rset(struct smtp_session *s)
}
static void
-smtp_proceed_helo(struct smtp_session *s, int cmd, char *args)
+smtp_proceed_helo(struct smtp_session *s, const char *args)
{
(void)strlcpy(s->helo, args, sizeof(s->helo));
s->flags &= SF_SECURE | SF_AUTHENTICATED | SF_VERIFIED;
- if (cmd == CMD_EHLO) {
- s->flags |= SF_EHLO;
- s->flags |= SF_8BITMIME;
- }
smtp_enter_state(s, STATE_HELO);
- smtp_reply(s, "250%c%s Hello %s [%s], pleased to meet you",
- (s->flags & SF_EHLO) ? '-' : ' ',
+ smtp_reply(s, "250 %s Hello %s [%s], pleased to meet you",
s->smtpname,
s->helo,
ss_to_text(&s->ss));
+}
- if (s->flags & SF_EHLO) {
- smtp_reply(s, "250-8BITMIME");
- smtp_reply(s, "250-ENHANCEDSTATUSCODES");
- smtp_reply(s, "250-SIZE %zu", env->sc_maxsize);
- if (ADVERTISE_EXT_DSN(s))
- smtp_reply(s, "250-DSN");
- if (ADVERTISE_TLS(s))
- smtp_reply(s, "250-STARTTLS");
- if (ADVERTISE_AUTH(s))
- smtp_reply(s, "250-AUTH PLAIN LOGIN");
- smtp_reply(s, "250 HELP");
- }
+static void
+smtp_proceed_ehlo(struct smtp_session *s, const char *args)
+{
+ (void)strlcpy(s->helo, args, sizeof(s->helo));
+ s->flags &= SF_SECURE | SF_AUTHENTICATED | SF_VERIFIED;
+ s->flags |= SF_EHLO;
+ s->flags |= SF_8BITMIME;
+
+ smtp_enter_state(s, STATE_HELO);
+ smtp_reply(s, "250-%s Hello %s [%s], pleased to meet you",
+ s->smtpname,
+ s->helo,
+ ss_to_text(&s->ss));
+
+ smtp_reply(s, "250-8BITMIME");
+ smtp_reply(s, "250-ENHANCEDSTATUSCODES");
+ smtp_reply(s, "250-SIZE %zu", env->sc_maxsize);
+ if (ADVERTISE_EXT_DSN(s))
+ smtp_reply(s, "250-DSN");
+ if (ADVERTISE_TLS(s))
+ smtp_reply(s, "250-STARTTLS");
+ if (ADVERTISE_AUTH(s))
+ smtp_reply(s, "250-AUTH PLAIN LOGIN");
+ smtp_reply(s, "250 HELP");
}
static void
-smtp_proceed_auth(struct smtp_session *s, char *args)
+smtp_proceed_auth(struct smtp_session *s, const char *args)
{
+ char tmp[SMTP_LINE_MAX];
char *eom, *method;
- method = args;
- eom = strchr(args, ' ');
+ (void)strlcpy(tmp, args, sizeof tmp);
+
+ method = tmp;
+ eom = strchr(tmp, ' ');
if (eom == NULL)
- eom = strchr(args, '\t');
+ eom = strchr(tmp, '\t');
if (eom != NULL)
*eom++ = '\0';
if (strcasecmp(method, "PLAIN") == 0)
@@ -1411,7 +1566,7 @@ smtp_proceed_auth(struct smtp_session *s, char *args)
}
static void
-smtp_proceed_starttls(struct smtp_session *s)
+smtp_proceed_starttls(struct smtp_session *s, const char *args)
{
smtp_reply(s, "220 %s: Ready to start TLS",
esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
@@ -1419,25 +1574,25 @@ smtp_proceed_starttls(struct smtp_session *s)
}
static void
-smtp_proceed_mail_from(struct smtp_session *s, char *args)
+smtp_proceed_mail_from(struct smtp_session *s, const char *args)
{
smtp_tx_mail_from(s->tx, args);
}
static void
-smtp_proceed_rcpt_to(struct smtp_session *s, char *args)
+smtp_proceed_rcpt_to(struct smtp_session *s, const char *args)
{
smtp_tx_rcpt_to(s->tx, args);
}
static void
-smtp_proceed_data(struct smtp_session *s)
+smtp_proceed_data(struct smtp_session *s, const char *args)
{
smtp_tx_open_message(s->tx);
}
static void
-smtp_proceed_quit(struct smtp_session *s)
+smtp_proceed_quit(struct smtp_session *s, const char *args)
{
smtp_reply(s, "221 %s: Bye",
esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
@@ -1445,14 +1600,14 @@ smtp_proceed_quit(struct smtp_session *s)
}
static void
-smtp_proceed_noop(struct smtp_session *s)
+smtp_proceed_noop(struct smtp_session *s, const char *args)
{
smtp_reply(s, "250 %s: Ok",
esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
}
static void
-smtp_proceed_help(struct smtp_session *s)
+smtp_proceed_help(struct smtp_session *s, const char *args)
{
smtp_reply(s, "214- This is " SMTPD_NAME);
smtp_reply(s, "214- To report bugs in the implementation, "
@@ -1463,7 +1618,7 @@ smtp_proceed_help(struct smtp_session *s)
}
static void
-smtp_proceed_wiz(struct smtp_session *s)
+smtp_proceed_wiz(struct smtp_session *s, const char *args)
{
smtp_reply(s, "500 %s %s: this feature is not supported yet ;-)",
esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
@@ -1632,6 +1787,12 @@ smtp_connected(struct smtp_session *s)
return;
}
+ smtp_filter_phase(FILTER_CONNECTED, s, ss_to_text(&s->ss));
+}
+
+static void
+smtp_proceed_connected(struct smtp_session *s)
+{
smtp_send_banner(s);
}
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 7a41dc74fe7..e59dd9ac311 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.568 2018/11/02 17:20:22 gilles Exp $ */
+/* $OpenBSD: smtpd.h,v 1.569 2018/11/03 13:42:24 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -315,6 +315,8 @@ enum imsg_type {
IMSG_SMTP_REPORT_PROTOCOL_CLIENT,
IMSG_SMTP_REPORT_PROTOCOL_SERVER,
+ IMSG_SMTP_FILTER,
+
IMSG_CA_PRIVENC,
IMSG_CA_PRIVDEC
};
@@ -390,6 +392,23 @@ enum expand_type {
EXPAND_ERROR,
};
+enum filter_phase {
+ FILTER_CONNECTED = 0,
+ FILTER_HELO,
+ FILTER_EHLO,
+ FILTER_STARTTLS,
+ FILTER_AUTH,
+ FILTER_MAIL_FROM,
+ FILTER_RCPT_TO,
+ FILTER_DATA,
+ FILTER_RSET,
+ FILTER_QUIT,
+ FILTER_NOOP,
+ FILTER_HELP,
+ FILTER_WIZ,
+ FILTER_PHASES_COUNT /* must be last */
+};
+
struct expandnode {
RB_ENTRY(expandnode) entry;
TAILQ_ENTRY(expandnode) tq_entry;
@@ -562,6 +581,8 @@ struct smtpd {
TAILQ_HEAD(listenerlist, listener) *sc_listeners;
TAILQ_HEAD(rulelist, rule) *sc_rules;
+ TAILQ_HEAD(filterrules, filter_rule) sc_filter_rules[FILTER_PHASES_COUNT];
+
struct dict *sc_dispatchers;
struct dispatcher *sc_dispatcher_bounce;
@@ -999,6 +1020,29 @@ struct processor {
const char *chroot;
};
+struct filter_rule {
+ TAILQ_ENTRY(filter_rule) entry;
+
+ enum filter_phase phase;
+ char *reject;
+ char *disconnect;
+ char *rewrite;
+ char *filter;
+
+ int8_t not_table;
+ struct table *table;
+
+ int8_t not_regex;
+ struct table *regex;
+};
+
+enum filter_status {
+ FILTER_PROCEED,
+ FILTER_REWRITE,
+ FILTER_REJECT,
+ FILTER_DISCONNECT,
+};
+
enum ca_resp_status {
CA_OK,
CA_FAIL
@@ -1259,6 +1303,10 @@ void lka_report_smtp_protocol_client(time_t, uint64_t, const char *);
void lka_report_smtp_protocol_server(time_t, uint64_t, const char *);
+/* lka_filter.c */
+void lka_filter(uint64_t, enum filter_phase, const char *);
+
+
/* lka_session.c */
void lka_session(uint64_t, struct envelope *);
void lka_session_forward_reply(struct forward_req *, int);
diff --git a/usr.sbin/smtpd/smtpd/Makefile b/usr.sbin/smtpd/smtpd/Makefile
index 96bad9f8264..f7d5e127a14 100644
--- a/usr.sbin/smtpd/smtpd/Makefile
+++ b/usr.sbin/smtpd/smtpd/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.95 2018/11/01 14:48:49 gilles Exp $
+# $OpenBSD: Makefile,v 1.96 2018/11/03 13:42:24 gilles Exp $
.PATH: ${.CURDIR}/..
@@ -22,6 +22,7 @@ SRCS+= iobuf.c
SRCS+= ioev.c
SRCS+= limit.c
SRCS+= lka.c
+SRCS+= lka_filter.c
SRCS+= lka_proc.c
SRCS+= lka_report.c
SRCS+= lka_session.c