diff options
author | Gilles Chehade <gilles@cvs.openbsd.org> | 2018-12-21 17:04:47 +0000 |
---|---|---|
committer | Gilles Chehade <gilles@cvs.openbsd.org> | 2018-12-21 17:04:47 +0000 |
commit | 737aaa76d2dcfa5576adadadb19f27c7a3898b12 (patch) | |
tree | 29a81a413fe12b43ef4b575393917e92255c1e65 | |
parent | 7928109223463f24bfe9976dc7a663ec40d4f32f (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.c | 156 | ||||
-rw-r--r-- | usr.sbin/smtpd/parse.y | 107 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 23 |
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 { |