On Thu, Feb 11, 2016 at 05:28:50PM -0500, Peter Bisroev wrote:
> 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.
>
I only skimmed through your diff, I need to apply it and read in
context but I like it a lot.
I'll test today and come back with comments once I've spent more
time reading it ;-)
Thanks
> 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;
>
--
Gilles Chehade
https://www.poolp.org @poolpOrg