summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGilles Chehade <gilles@cvs.openbsd.org>2018-12-21 17:04:47 +0000
committerGilles Chehade <gilles@cvs.openbsd.org>2018-12-21 17:04:47 +0000
commit737aaa76d2dcfa5576adadadb19f27c7a3898b12 (patch)
tree29a81a413fe12b43ef4b575393917e92255c1e65
parent7928109223463f24bfe9976dc7a663ec40d4f32f (diff)
implement some additional builtin filters:
check-src-{table,regex}, check-rdns-{table,regex} make sure that these builtins may be used at all phases
-rw-r--r--usr.sbin/smtpd/lka_filter.c156
-rw-r--r--usr.sbin/smtpd/parse.y107
-rw-r--r--usr.sbin/smtpd/smtpd.h23
3 files changed, 165 insertions, 121 deletions
diff --git a/usr.sbin/smtpd/lka_filter.c b/usr.sbin/smtpd/lka_filter.c
index 7a5b9fa7fbe..bdeac000b96 100644
--- a/usr.sbin/smtpd/lka_filter.c
+++ b/usr.sbin/smtpd/lka_filter.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lka_filter.c,v 1.16 2018/12/21 14:33:52 gilles Exp $ */
+/* $OpenBSD: lka_filter.c,v 1.17 2018/12/21 17:04:46 gilles Exp $ */
/*
* Copyright (c) 2018 Gilles Chehade <gilles@poolp.org>
@@ -35,8 +35,10 @@
#include "smtpd.h"
#include "log.h"
-struct filter;
+#define PROTOCOL_VERSION 1
+struct filter;
+struct filter_session;
static void filter_protocol(uint64_t, enum filter_phase, const char *);
static void filter_protocol_next(uint64_t, uint64_t, const char *);
static void filter_protocol_query(struct filter *, uint64_t, uint64_t, const char *, const char *);
@@ -45,11 +47,11 @@ static void filter_data(uint64_t, const char *);
static void filter_data_next(uint64_t, uint64_t, const char *);
static void filter_data_query(struct filter *, uint64_t, uint64_t, const char *);
-static int filter_builtins_notimpl(struct filter *, uint64_t, const char *);
-static int filter_builtins_connect(struct filter *, uint64_t, const char *);
-static int filter_builtins_helo(struct filter *, uint64_t, const char *);
-static int filter_builtins_mail_from(struct filter *, uint64_t, const char *);
-static int filter_builtins_rcpt_to(struct filter *, uint64_t, const char *);
+static int filter_builtins_notimpl(struct filter_session *, struct filter *, uint64_t, const char *);
+static int filter_builtins_connect(struct filter_session *, struct filter *, uint64_t, const char *);
+static int filter_builtins_helo(struct filter_session *, struct filter *, uint64_t, const char *);
+static int filter_builtins_mail_from(struct filter_session *, struct filter *, uint64_t, const char *);
+static int filter_builtins_rcpt_to(struct filter_session *, struct filter *, uint64_t, const char *);
static void filter_result_proceed(uint64_t);
static void filter_result_rewrite(uint64_t, const char *);
@@ -60,12 +62,23 @@ static void filter_session_io(struct io *, int, void *);
int lka_filter_process_response(const char *, const char *);
-#define PROTOCOL_VERSION 1
+struct filter_session {
+ uint64_t id;
+ struct io *io;
+
+ char *filter_name;
+ struct sockaddr_storage ss_src;
+ struct sockaddr_storage ss_dest;
+ char *rdns;
+ int fcrdns;
+
+ enum filter_phase phase;
+};
static struct filter_exec {
enum filter_phase phase;
const char *phase_name;
- int (*func)(struct filter *, uint64_t, const char *);
+ int (*func)(struct filter_session *, struct filter *, uint64_t, const char *);
} filter_execs[FILTER_PHASES_COUNT] = {
{ FILTER_CONNECT, "connect", filter_builtins_connect },
{ FILTER_HELO, "helo", filter_builtins_helo },
@@ -84,19 +97,6 @@ static struct filter_exec {
{ FILTER_COMMIT, "commit", filter_builtins_notimpl },
};
-struct filter_session {
- uint64_t id;
- struct io *io;
-
- char *filter_name;
- struct sockaddr_storage ss_src;
- struct sockaddr_storage ss_dest;
- char *rdns;
- int fcrdns;
-
- enum filter_phase phase;
-};
-
struct filter {
uint64_t id;
uint32_t phases;
@@ -125,7 +125,6 @@ static int inited;
static struct dict filter_chains;
-
void
lka_filter_init(void)
{
@@ -496,7 +495,7 @@ filter_protocol(uint64_t reqid, enum filter_phase phase, const char *param)
return; /* deferred */
}
- if (filter_execs[i].func(filter, reqid, param)) {
+ if (filter_execs[i].func(fs, filter, reqid, param)) {
if (filter->config->rewrite)
filter_result_rewrite(reqid, filter->config->rewrite);
else if (filter->config->disconnect)
@@ -534,7 +533,7 @@ filter_protocol_next(uint64_t token, uint64_t reqid, const char *param)
return; /* deferred */
}
- if (filter_execs[fs->phase].func(filter, reqid, param)) {
+ if (filter_execs[fs->phase].func(fs, filter, reqid, param)) {
if (filter->config->rewrite)
filter_result_rewrite(reqid, filter->config->rewrite);
else if (filter->config->disconnect)
@@ -696,27 +695,53 @@ filter_result_disconnect(uint64_t reqid, const char *message)
/* below is code for builtin filters */
static int
-filter_check_table(struct filter *filter, enum table_service kind, const char *key)
+filter_check_rdns_table(struct filter *filter, enum table_service kind, const char *key)
{
int ret = 0;
- if (filter->config->table) {
- if (table_lookup(filter->config->table, NULL, key, kind, NULL) > 0)
+ if (filter->config->rdns_table) {
+ if (table_lookup(filter->config->rdns_table, NULL, key, kind, NULL) > 0)
ret = 1;
- ret = filter->config->not_table < 0 ? !ret : ret;
+ ret = filter->config->not_rdns_table < 0 ? !ret : ret;
}
return ret;
}
static int
-filter_check_regex(struct filter *filter, const char *key)
+filter_check_rdns_regex(struct filter *filter, const char *key)
{
int ret = 0;
- if (filter->config->regex) {
- if (table_lookup(filter->config->regex, NULL, key, K_REGEX, NULL) > 0)
+ if (filter->config->rdns_regex) {
+ if (table_lookup(filter->config->rdns_regex, NULL, key, K_REGEX, NULL) > 0)
ret = 1;
- ret = filter->config->not_regex < 0 ? !ret : ret;
+ ret = filter->config->not_rdns_regex < 0 ? !ret : ret;
+ }
+ return ret;
+}
+
+static int
+filter_check_src_table(struct filter *filter, enum table_service kind, const char *key)
+{
+ int ret = 0;
+
+ if (filter->config->src_table) {
+ if (table_lookup(filter->config->src_table, NULL, key, kind, NULL) > 0)
+ ret = 1;
+ ret = filter->config->not_src_table < 0 ? !ret : ret;
+ }
+ return ret;
+}
+
+static int
+filter_check_src_regex(struct filter *filter, const char *key)
+{
+ int ret = 0;
+
+ if (filter->config->src_regex) {
+ if (table_lookup(filter->config->src_regex, NULL, key, K_REGEX, NULL) > 0)
+ ret = 1;
+ ret = filter->config->not_src_regex < 0 ? !ret : ret;
}
return ret;
}
@@ -750,73 +775,44 @@ filter_check_rdns(struct filter *filter, const char *hostname)
}
static int
-filter_builtins_notimpl(struct filter *filter, uint64_t reqid, const char *param)
+filter_builtins_notimpl(struct filter_session *fs, struct filter *filter, uint64_t reqid, const char *param)
{
return 0;
}
static int
-filter_builtins_connect(struct filter *filter, uint64_t reqid, const char *param)
+filter_builtins_global(struct filter_session *fs, struct filter *filter, uint64_t reqid, const char *param)
{
- struct filter_session *fs;
-
- fs = tree_xget(&sessions, reqid);
- if (filter_check_table(filter, K_NETADDR, param) ||
- filter_check_regex(filter, param) ||
+ if (filter_check_fcrdns(filter, fs->fcrdns) ||
filter_check_rdns(filter, fs->rdns) ||
- filter_check_fcrdns(filter, fs->fcrdns))
+ filter_check_rdns_table(filter, K_DOMAIN, fs->rdns) ||
+ filter_check_rdns_regex(filter, fs->rdns) ||
+ filter_check_src_table(filter, K_NETADDR, fs->rdns) ||
+ filter_check_src_regex(filter, fs->rdns))
return 1;
return 0;
}
static int
-filter_builtins_helo(struct filter *filter, uint64_t reqid, const char *param)
+filter_builtins_connect(struct filter_session *fs, struct filter *filter, uint64_t reqid, const char *param)
{
- struct filter_session *fs;
-
- fs = tree_xget(&sessions, reqid);
- if (filter_check_table(filter, K_DOMAIN, param) ||
- filter_check_regex(filter, param) ||
- filter_check_rdns(filter, fs->rdns) ||
- filter_check_fcrdns(filter, fs->fcrdns))
- return 1;
- return 0;
+ return filter_builtins_global(fs, filter, reqid, param);
}
static int
-filter_builtins_mail_from(struct filter *filter, uint64_t reqid, const char *param)
+filter_builtins_helo(struct filter_session *fs, struct filter *filter, uint64_t reqid, const char *param)
{
- char buffer[SMTPD_MAXMAILADDRSIZE];
- struct filter_session *fs;
-
- fs = tree_xget(&sessions, reqid);
- (void)strlcpy(buffer, param+1, sizeof(buffer));
- buffer[strcspn(buffer, ">")] = '\0';
- param = buffer;
-
- if (filter_check_table(filter, K_MAILADDR, param) ||
- filter_check_regex(filter, param) ||
- filter_check_rdns(filter, fs->rdns) ||
- filter_check_fcrdns(filter, fs->fcrdns))
- return 1;
- return 0;
+ return filter_builtins_global(fs, filter, reqid, param);
}
static int
-filter_builtins_rcpt_to(struct filter *filter, uint64_t reqid, const char *param)
+filter_builtins_mail_from(struct filter_session *fs, struct filter *filter, uint64_t reqid, const char *param)
{
- char buffer[SMTPD_MAXMAILADDRSIZE];
- struct filter_session *fs;
-
- fs = tree_xget(&sessions, reqid);
- (void)strlcpy(buffer, param+1, sizeof(buffer));
- buffer[strcspn(buffer, ">")] = '\0';
- param = buffer;
+ return filter_builtins_global(fs, filter, reqid, param);
+}
- if (filter_check_table(filter, K_MAILADDR, param) ||
- filter_check_regex(filter, param) ||
- filter_check_rdns(filter, fs->rdns) ||
- filter_check_fcrdns(filter, fs->fcrdns))
- return 1;
- return 0;
+static int
+filter_builtins_rcpt_to(struct filter_session *fs, struct filter *filter, uint64_t reqid, const char *param)
+{
+ return filter_builtins_global(fs, filter, reqid, param);
}
diff --git a/usr.sbin/smtpd/parse.y b/usr.sbin/smtpd/parse.y
index bb437d34f15..8b4461e8e7d 100644
--- a/usr.sbin/smtpd/parse.y
+++ b/usr.sbin/smtpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.238 2018/12/21 14:33:52 gilles Exp $ */
+/* $OpenBSD: parse.y,v 1.239 2018/12/21 17:04:46 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -175,7 +175,7 @@ typedef struct {
%token ACTION ALIAS ANY ARROW AUTH AUTH_OPTIONAL
%token BACKUP BOUNCE BUILTIN
%token CA CERT CHAIN CHROOT CIPHERS COMMIT COMPRESSION CONNECT
-%token CHECK_FCRDNS CHECK_RDNS CHECK_REGEX CHECK_TABLE
+%token CHECK_FCRDNS CHECK_RDNS CHECK_RDNS_REGEX CHECK_RDNS_TABLE CHECK_SRC_REGEX CHECK_SRC_TABLE
%token DATA DATA_LINE DHE DISCONNECT DOMAIN
%token EHLO ENABLE ENCRYPTION ERROR EXPAND_ONLY
%token FILTER FOR FORWARD_ONLY FROM
@@ -1124,20 +1124,6 @@ REJECT STRING {
}
;
-filter_phase_check_table:
-negation CHECK_TABLE tables {
- filter_config->not_table = $1 ? -1 : 1;
- filter_config->table = $3;
-}
-;
-
-filter_phase_check_regex:
-negation CHECK_REGEX tables {
- filter_config->not_regex = $1 ? -1 : 1;
- filter_config->regex = $3;
-}
-;
-
filter_phase_check_fcrdns:
negation CHECK_FCRDNS {
filter_config->not_fcrdns = $1 ? -1 : 1;
@@ -1152,8 +1138,67 @@ negation CHECK_RDNS {
}
;
+filter_phase_check_rdns_table:
+negation CHECK_RDNS_TABLE tables {
+ filter_config->not_rdns_table = $1 ? -1 : 1;
+ filter_config->rdns_table = $3;
+}
+;
+filter_phase_check_rdns_regex:
+negation CHECK_RDNS_REGEX tables {
+ filter_config->not_rdns_regex = $1 ? -1 : 1;
+ filter_config->rdns_regex = $3;
+}
+;
+
+filter_phase_check_src_table:
+negation CHECK_SRC_TABLE tables {
+ filter_config->not_src_table = $1 ? -1 : 1;
+ filter_config->src_table = $3;
+}
+;
+filter_phase_check_src_regex:
+negation CHECK_SRC_REGEX tables {
+ filter_config->not_src_regex = $1 ? -1 : 1;
+ filter_config->src_regex = $3;
+}
+;
+
+filter_phase_global_options:
+filter_phase_check_fcrdns |
+filter_phase_check_rdns |
+filter_phase_check_rdns_regex |
+filter_phase_check_rdns_table |
+filter_phase_check_src_regex |
+filter_phase_check_src_table;
+
filter_phase_connect_options:
-filter_phase_check_table | filter_phase_check_regex | filter_phase_check_fcrdns | filter_phase_check_rdns;
+filter_phase_global_options;
+
+filter_phase_helo_options:
+filter_phase_global_options;
+
+filter_phase_mail_from_options:
+filter_phase_global_options;
+
+filter_phase_rcpt_to_options:
+filter_phase_global_options;
+
+filter_phase_data_options:
+filter_phase_global_options;
+
+filter_phase_quit_options:
+filter_phase_global_options;
+
+filter_phase_rset_options:
+filter_phase_global_options;
+
+filter_phase_noop_options:
+filter_phase_global_options;
+
+filter_phase_commit_options:
+filter_phase_global_options;
+
filter_phase_connect:
CONNECT {
@@ -1161,8 +1206,6 @@ CONNECT {
} filter_phase_connect_options filter_action_builtin
;
-filter_phase_helo_options:
-filter_phase_check_table | filter_phase_check_regex | filter_phase_check_fcrdns | filter_phase_check_rdns;
filter_phase_helo:
HELO {
@@ -1176,18 +1219,12 @@ EHLO {
} filter_phase_helo_options filter_action_builtin
;
-filter_phase_mail_from_options:
-filter_phase_check_table | filter_phase_check_regex | filter_phase_check_fcrdns | filter_phase_check_rdns;
-
filter_phase_mail_from:
MAIL_FROM {
filter_config->phase = FILTER_MAIL_FROM;
} filter_phase_mail_from_options filter_action_builtin
;
-filter_phase_rcpt_to_options:
-filter_phase_check_table | filter_phase_check_regex | filter_phase_check_fcrdns | filter_phase_check_rdns;
-
filter_phase_rcpt_to:
RCPT_TO {
filter_config->phase = FILTER_RCPT_TO;
@@ -1197,37 +1234,39 @@ RCPT_TO {
filter_phase_data:
DATA {
filter_config->phase = FILTER_DATA;
-} filter_action_builtin
+} filter_phase_data_options filter_action_builtin
;
+/*
filter_phase_data_line:
DATA_LINE {
filter_config->phase = FILTER_DATA_LINE;
} filter_action_builtin
;
+*/
filter_phase_quit:
QUIT {
filter_config->phase = FILTER_QUIT;
-} filter_action_builtin
+} filter_phase_quit_options filter_action_builtin
;
filter_phase_rset:
RSET {
filter_config->phase = FILTER_RSET;
-} filter_action_builtin
+} filter_phase_rset_options filter_action_builtin
;
filter_phase_noop:
NOOP {
filter_config->phase = FILTER_NOOP;
-} filter_action_builtin
+} filter_phase_noop_options filter_action_builtin
;
filter_phase_commit:
COMMIT {
filter_config->phase = FILTER_COMMIT;
-} filter_action_builtin
+} filter_phase_commit_options filter_action_builtin
;
@@ -1239,7 +1278,7 @@ filter_phase_connect
| filter_phase_mail_from
| filter_phase_rcpt_to
| filter_phase_data
-| filter_phase_data_line
+/*| filter_phase_data_line*/
| filter_phase_quit
| filter_phase_noop
| filter_phase_rset
@@ -1942,8 +1981,10 @@ lookup(char *s)
{ "chain", CHAIN },
{ "check-fcrdns", CHECK_FCRDNS },
{ "check-rdns", CHECK_RDNS },
- { "check-regex", CHECK_REGEX },
- { "check-table", CHECK_TABLE },
+ { "check-rdns-regex", CHECK_RDNS_REGEX },
+ { "check-rdns-table", CHECK_RDNS_TABLE },
+ { "check-src-regex", CHECK_SRC_REGEX },
+ { "check-src-table", CHECK_SRC_TABLE },
{ "chroot", CHROOT },
{ "ciphers", CIPHERS },
{ "commit", COMMIT },
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 143859c3ca2..070979a7f23 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.595 2018/12/21 14:33:52 gilles Exp $ */
+/* $OpenBSD: smtpd.h,v 1.596 2018/12/21 17:04:46 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -1058,17 +1058,24 @@ struct filter_config {
size_t chain_size;
struct dict chain_procs;
- int8_t not_table;
- struct table *table;
-
- int8_t not_regex;
- struct table *regex;
+ int8_t not_fcrdns;
+ int8_t fcrdns;
int8_t not_rdns;
int8_t rdns;
- int8_t not_fcrdns;
- int8_t fcrdns;
+ int8_t not_rdns_table;
+ struct table *rdns_table;
+
+ int8_t not_rdns_regex;
+ struct table *rdns_regex;
+
+ int8_t not_src_table;
+ struct table *src_table;
+
+ int8_t not_src_regex;
+ struct table *src_regex;
+
};
enum filter_status {