Hi Gilles,
Please find my diff inline to enable "listen on socket" feature that we have
discussed. I have tested the diff with currently two supported listen options
for this listener, mask-sender and filter. Everything seems to be working OK.
These are the summary of the changes:
* Parser was adjusted to support "listen on socket", should be easier to
extend to new listener types.
* Reusing config_listener().
* struct smtpd has a new member sc_sock_listener to be used by smtp_enqueu()
* If "listen on socket" was not specified in the config file, a default
socket listener will be created in parse_config()
* I also removed "struct listener l" from parse.y as it was not being used
anywhere.
* I have tried to stick to the coding style in the source, and tried to keep
the diff as small as possible. Please let me know if something is off and
I will fix it.
If these changes look OK to you, I will create a diff for the man page and
send it through.
Thank you!
--peter
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/parse.y,v
retrieving revision 1.181
diff -u -p -r1.181 parse.y
--- parse.y 18 Jan 2016 09:19:41 -0000 1.181
+++ parse.y 11 Feb 2016 20:59:11 -0000
@@ -97,7 +97,6 @@ static int errors = 0;
struct filter_conf *filter = NULL;
struct table *table = NULL;
struct rule *rule = NULL;
-struct listener l;
struct mta_limits *limits;
static struct pki *pki;
static struct ca *sca;
@@ -139,8 +138,9 @@ static struct listen_opts {
uint32_t options;
} listen_opts;
-static void create_listener(struct listenerlist *, struct listen_opts *);
-static void config_listener(struct listener *, struct listen_opts *);
+static struct listener *create_sock_listener(struct listen_opts *);
+static void create_if_listener(struct listenerlist *, struct listen_opts *);
+static void config_listener(struct listener *, struct listen_opts *);
struct listener *host_v4(const char *, in_port_t);
struct listener *host_v6(const char *, in_port_t);
@@ -156,6 +156,9 @@ static struct filter_conf *create_filter
static struct filter_conf *create_filter_chain(char *);
static int add_filter_arg(struct filter_conf *, char *);
+static int config_lo_filter(struct listen_opts *, char *);
+static int config_lo_mask_source(struct listen_opts *);
+
typedef struct {
union {
int64_t number;
@@ -175,7 +178,7 @@ typedef struct {
%token ACCEPT REJECT INCLUDE ERROR MDA FROM FOR SOURCE MTA PKI SCHEDULER
%token ARROW AUTH TLS LOCAL VIRTUAL TAG TAGGED ALIAS FILTER KEY CA DHPARAMS
%token AUTH_OPTIONAL TLS_REQUIRE USERBASE SENDER SENDERS MASK_SOURCE VERIFY FORWARDONLY RECIPIENT
-%token CIPHERS RECEIVEDAUTH MASQUERADE ENQUEUER
+%token CIPHERS RECEIVEDAUTH MASQUERADE SOCKET
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.table> table
@@ -403,7 +406,19 @@ pki : opt_pki pki
| /* empty */
;
-opt_listen : INET4 {
+opt_sock_listen : FILTER STRING {
+ if (config_lo_filter(&listen_opts, $2)) {
+ YYERROR;
+ }
+ }
+ | MASK_SOURCE {
+ if (config_lo_mask_source(&listen_opts)) {
+ YYERROR;
+ }
+ }
+ ;
+
+opt_if_listen : INET4 {
if (listen_opts.options & LO_FAMILY) {
yyerror("address family already specified");
YYERROR;
@@ -451,13 +466,10 @@ opt_listen : INET4 {
listen_opts.port = $2;
}
| FILTER STRING {
- if (listen_opts.options & LO_FILTER) {
- yyerror("filter already specified");
+ if (config_lo_filter(&listen_opts, $2)) {
YYERROR;
}
- listen_opts.options |= LO_FILTER;
- listen_opts.filtername = $2;
- }
+}
| SMTPS {
if (listen_opts.options & LO_SSL) {
yyerror("TLS mode already specified");
@@ -596,12 +608,9 @@ opt_listen : INET4 {
listen_opts.hostnametable = t;
}
| MASK_SOURCE {
- if (listen_opts.options & LO_MASKSOURCE) {
- yyerror("mask-source already specified");
+ if (config_lo_mask_source(&listen_opts)) {
YYERROR;
}
- listen_opts.options |= LO_MASKSOURCE;
- listen_opts.flags |= F_MASK_SOURCE;
}
| RECEIVEDAUTH {
if (listen_opts.options & LO_RECEIVEDAUTH) {
@@ -653,7 +662,33 @@ opt_listen : INET4 {
}
;
-listen : opt_listen listen
+listener_type : socket_listener
+ | interface_listener
+ ;
+
+socket_listener : SOCKET sock_listen {
+ if (conf->sc_sock_listener) {
+ yyerror("socket listener already configured");
+ YYERROR;
+ }
+ conf->sc_sock_listener = create_sock_listener(&listen_opts);
+ }
+ ;
+
+interface_listener:
+ STRING if_listen {
+ listen_opts.family = AF_UNSPEC;
+ listen_opts.flags |= F_EXT_DSN;
+ listen_opts.ifx = $1;
+ create_if_listener(conf->sc_listeners, &listen_opts);
+ }
+ ;
+
+sock_listen : opt_sock_listen sock_listen
+ | /* empty */
+ ;
+
+if_listen : opt_if_listen if_listen
| /* empty */
;
@@ -846,28 +881,8 @@ main : BOUNCEWARN {
} limits_mta
| LIMIT SCHEDULER limits_scheduler
| LISTEN {
- memset(&l, 0, sizeof l);
memset(&listen_opts, 0, sizeof listen_opts);
- listen_opts.family = AF_UNSPEC;
- listen_opts.flags |= F_EXT_DSN;
- } ON STRING listen {
- listen_opts.ifx = $4;
- create_listener(conf->sc_listeners, &listen_opts);
- }
- | ENQUEUER FILTER STRING {
- if (dict_get(&conf->sc_filters, $3) == NULL) {
- yyerror("undefined filter \"%s\"", $3);
- free($3);
- YYERROR;
- }
- if (strlcpy(conf->sc_enqueue_filter, $3,
- sizeof conf->sc_enqueue_filter)
- >= sizeof conf->sc_enqueue_filter) {
- free($3);
- YYERROR;
- }
- free($3);
- }
+ } ON listener_type
| FILTER STRING STRING {
if (!strcmp($3, "chain")) {
free($3);
@@ -1449,7 +1464,6 @@ lookup(char *s)
{ "dhparams", DHPARAMS },
{ "domain", DOMAIN },
{ "encryption", ENCRYPTION },
- { "enqueuer", ENQUEUER },
{ "expire", EXPIRE },
{ "filter", FILTER },
{ "for", FOR },
@@ -1489,6 +1503,7 @@ lookup(char *s)
{ "senders", SENDERS },
{ "session", SESSION },
{ "smtps", SMTPS },
+ { "socket", SOCKET },
{ "source", SOURCE },
{ "table", TABLE },
{ "tag", TAG },
@@ -1945,6 +1960,12 @@ parse_config(struct smtpd *x_conf, const
popfile();
endservent();
+ /* If the socket listener was not configured, create a default one. */
+ if (!conf->sc_sock_listener) {
+ memset(&listen_opts, 0, sizeof listen_opts);
+ conf->sc_sock_listener = create_sock_listener(&listen_opts);
+ }
+
/* Free macros and check which have not been used. */
for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
next = TAILQ_NEXT(sym, entry);
@@ -2046,8 +2067,21 @@ symget(const char *nam)
return (NULL);
}
+static struct listener *
+create_sock_listener(struct listen_opts *lo)
+{
+ struct listener *l = xcalloc(1, sizeof(*l), "create_sock_listener");
+ lo->tag = "local";
+ lo->hostname = conf->sc_hostname;
+ l->ss.ss_family = AF_LOCAL;
+ l->ss.ss_len = sizeof(struct sockaddr *);
+ config_listener(l, lo);
+
+ return (l);
+}
+
static void
-create_listener(struct listenerlist *ll, struct listen_opts *lo)
+create_if_listener(struct listenerlist *ll, struct listen_opts *lo)
{
uint16_t flags;
@@ -2560,3 +2594,28 @@ add_filter_arg(struct filter_conf *f, ch
return (1);
}
+
+static int
+config_lo_filter(struct listen_opts *lo, char *filter_name) {
+ if (lo->options & LO_FILTER) {
+ yyerror("filter already specified");
+ return -1;
+ }
+ lo->options |= LO_FILTER;
+ lo->filtername = filter_name;
+
+ return 0;
+}
+
+static int
+config_lo_mask_source(struct listen_opts *lo) {
+ if (lo->options & LO_MASKSOURCE) {
+ yyerror("mask-source already specified");
+ return -1;
+ }
+ lo->options |= LO_MASKSOURCE;
+ lo->flags |= F_MASK_SOURCE;
+
+ return 0;
+}
+
Index: smtp.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtp.c,v
retrieving revision 1.152
diff -u -p -r1.152 smtp.c
--- smtp.c 8 Jan 2016 21:31:06 -0000 1.152
+++ smtp.c 11 Feb 2016 20:59:11 -0000
@@ -219,20 +219,9 @@ smtp_resume(void)
static int
smtp_enqueue(uid_t *euid)
{
- static struct listener local, *listener = NULL;
- char buf[HOST_NAME_MAX+1], *hostname;
- int fd[2];
-
- if (listener == NULL) {
- listener = &local;
- (void)strlcpy(listener->tag, "local", sizeof(listener->tag));
- listener->ss.ss_family = AF_LOCAL;
- listener->ss.ss_len = sizeof(struct sockaddr *);
- (void)strlcpy(listener->hostname, env->sc_hostname,
- sizeof(listener->hostname));
- (void)strlcpy(listener->filter, env->sc_enqueue_filter,
- sizeof listener->filter);
- }
+ struct listener *listener = env->sc_sock_listener;
+ char buf[HOST_NAME_MAX+1], *hostname;
+ int fd[2];
/*
* Some enqueue requests buffered in IMSG may still arrive even after
Index: smtpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd.h,v
retrieving revision 1.511
diff -u -p -r1.511 smtpd.h
--- smtpd.h 5 Feb 2016 19:21:04 -0000 1.511
+++ smtpd.h 11 Feb 2016 20:59:11 -0000
@@ -613,6 +613,9 @@ struct smtpd {
time_t sc_uptime;
+ /* This is a listener for a local socket used by smtp_enqueue(). */
+ struct listener *sc_sock_listener;
+
TAILQ_HEAD(listenerlist, listener) *sc_listeners;
TAILQ_HEAD(rulelist, rule) *sc_rules;