On Thu, 2021-04-29 at 11:22 +1000, Antonino Sidoti wrote:
> Hello,
> 
> I was wondering what options are available to monitor OpenBSD SMTPD? Can SNMP 
> be utilise? My monitoring system is PRTG and I am using that for most of my 
> systems. Can someone share their way of
> monitoring please? I run two OpenSMTP mail servers and would very much like 
> to get some insight as to how they are performing day to day. 
> 
> Thanks
> 
> Antonino Sidoti

I've build the following diff some time ago. But isn't going in as is,
because the other devs want something like the filter interface for this
feature, which is understandable. But that needs to be thought out fully
and then also implemented, which might take some time. I'm currently
focussing on other parts of the snmp stack before I want to venture into
smtp processes again.

Anyway, the diff adds basic agentx support around the NETWORK-SERVICE-
MIB (RFC2788) and the MTA-MIB (RFC2789). Feel free to use it, test it,
and to report bugs. It will probably help keep things in shape, or maybe
even improve its shape, until we finally have that external process.
Keep in mind that this lacks the proper peer review expected from most
OpenBSD base code.

Usage:
Let net-snmpd (snmpd(8) currently has no agentx support) create an
agentx socket:
  master agentx
smtpd connects via the parent process, which is root, so no need for
custom agentXPerms.
Then you just add the following keyword to smtpd.conf
  agentx
And you can walk the data:
martijn$ snmp walk 127.0.0.1 mib_2.27
mib_2.27.1.1.2.1 = STRING: OpenSMTPd
mib_2.27.1.1.3.1 = STRING: 
mib_2.27.1.1.4.1 = STRING: 6.9.0
mib_2.27.1.1.5.1 = Timeticks: (2100) 0:00:21.00
mib_2.27.1.1.6.1 = INTEGER: 1
mib_2.27.1.1.7.1 = Timeticks: (0) 0:00:00.00
mib_2.27.1.1.16.1 = STRING: OpenSMTPD is a FREE implementation of the 
server-side SMTP protocol as defined by RFC 5321, with some additional standard 
extensions. It allows ordinary machines to
exchange emails with other systems speaking the SMTP protocol.
mib_2.27.1.1.17.1 = STRING: 
martijn$ snmp walk 127.0.0.1 mib_2.28
mib_2.28.1.1.1.1 = Counter32: 0
mib_2.28.1.1.2.1 = Counter32: 0
mib_2.28.1.1.3.1 = Counter32: 0
mib_2.28.1.1.12.1 = Counter32: 0

You can set custom (agentx-master-)path and context as well.

If you have other applications running that uses the NETWORK-SERVICES
MIB and you want predictable indices from the applIndex you can set it
via the applIndex keyword. Keep in mind that your other applications
need to play nice with the indexAllocate system in any case.

If you're running on !OpenBSD let me know, I have some diffs to make
libagentx work on at least Ubuntu and maybe others.

martijn@

Index: agentx_control.c
===================================================================
RCS file: agentx_control.c
diff -N agentx_control.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ agentx_control.c    29 Apr 2021 05:22:14 -0000
@@ -0,0 +1,279 @@
+/*     $OpenBSD$ */
+
+/*
+ * Copyright (c) 2020 Martijn van Duren <[email protected]>
+ *
+ * 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/queue.h>
+#include <sys/socket.h>
+#include <sys/tree.h>
+#include <sys/uio.h>
+
+#include <agentx.h>
+#include <errno.h>
+#include <event.h>
+#include <imsg.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include "log.h"
+#include "smtpd.h"
+
+static void agentx_control_nofd(struct agentx *, void *, int);
+static void agentx_control_tryconnect(int, short, void *);
+static void agentx_control_read(int, short, void *);
+static void agentx_control_emptystring(struct agentx_varbind *);
+static void agentx_control_applName(struct agentx_varbind *);
+static void agentx_control_applVersion(struct agentx_varbind *);
+static void agentx_control_applUptime(struct agentx_varbind *);
+static void agentx_control_applOperStatus(struct agentx_varbind *);
+static void agentx_control_applLastChange(struct agentx_varbind *);
+static void agentx_control_applDescription(struct agentx_varbind *);
+static void agentx_control_applURL(struct agentx_varbind *);
+static void agentx_control_mtaReceivedMessages(struct agentx_varbind *);
+static void agentx_control_mtaStoredMessages(struct agentx_varbind *);
+static void agentx_control_mtaTransmittedMessages(struct agentx_varbind *);
+static void agentx_control_mtaLoopsDetected(struct agentx_varbind *);
+
+static struct agentx *sa;
+static struct agentx_session *sas;
+static struct agentx_context *sac;
+static struct agentx_region *application, *mta;
+static struct agentx_index *applIndex;
+static struct event connev, rev;
+
+extern struct stat_digest digest;
+
+#define APPLICATION AGENTX_MIB2, 27
+#define APPLTABLE APPLICATION, 1
+#define APPLENTRY APPLTABLE, 1
+#define APPLINDEX APPLENTRY, 1
+#define APPLNAME APPLENTRY, 2
+#define APPLDIRECTORYNAME APPLENTRY, 3
+#define APPLVERSION APPLENTRY, 4
+#define APPLUPTIME APPLENTRY, 5
+#define APPLOPERSTATUS APPLENTRY, 6
+#define APPLLASTCHANGE APPLENTRY, 7
+#define APPLINBOUNDASSOCIATIONS APPLENTRY, 8
+#define APPLOUTBOUNDASSOCIATIONS APPLENTRY, 9
+#define APPLACCUMULATEDINBOUNDASSOCIATIONS APPLENTRY, 10
+#define APPLACCUMULATEDOUTBOUNDASSOCIATIONS APPLENTRY, 11
+#define APPLLASTINBOUNDACTIVITY APPLENTRY, 12
+#define APPLlASTOUTBOUNDACTIVITY APPLENTRY, 13
+#define APPLREJECTEDINBOUNDASSOCIATIONS APPLENTRY, 14
+#define APPLFAILEDOUTBOUNDASSOCIATIONS APPLENTRY, 15
+#define APPLDESCRIPTION APPLENTRY, 16
+#define APPLURL APPLENTRY, 17
+#define MTA AGENTX_MIB2, 28
+#define MTATABLE MTA, 1
+#define MTAENTRY MTATABLE, 1
+#define MTARECEIVEDMESSAGES MTAENTRY, 1
+#define MTASTOREDMESSAGES MTAENTRY, 2
+#define MTATRANSMITTEDMESSAGES MTAENTRY, 3
+#define MTARECEIVEDVOLUME MTAENTRY, 4
+#define MTASTOREDVOLUME MTAENTRY, 5
+#define MTATRANSMITTEDVOLUME MTAENTRY, 6
+#define MTARECEIVEDRECIPIENTS MTAENTRY, 7
+#define MTASTOREDRECIPIENTS MTAENTRY, 8
+#define MTATRANSMITTEDRECIPIENTS MTAENTRY, 9
+#define MTASUCCESSFULCONVERTEDMESSAGES MTAENTRY, 10
+#define MTAFAILEDCONVERTEDMESSAGES MTAENTRY, 11
+#define MTALOOPSDETECTED MTAENTRY, 12
+
+void
+agentx_control(void)
+{
+       agentx_log_fatal = fatalx;
+       agentx_log_warn = log_warnx;
+       agentx_log_info = log_info;
+       agentx_log_debug = log_debug;
+
+       if ((sa = agentx(agentx_control_nofd, NULL)) == NULL)
+               fatal("Can't setup agentx");
+       if ((sas = agentx_session(sa, NULL, 0, "OpenSMTPd", 0)) == NULL)
+               fatal("Can't setup agentx session");
+       if ((sac = agentx_context(sas, env->sc_agentx->context)) == NULL)
+               fatal("Can't setup agentx context");
+
+        if ((application = agentx_region(sac,
+           AGENTX_OID(APPLICATION), 0)) == NULL)
+                fatal("agentx_mib application region");
+        if ((mta = agentx_region(sac,
+           AGENTX_OID(MTA, 28), 0)) == NULL)
+                fatal("agentx_mib application region");
+       switch (env->sc_agentx->applIndexType) {
+       case AGENTX_INDEX_TYPE_ANY:
+               if ((applIndex = agentx_index_integer_any(application,
+                   AGENTX_OID(APPLINDEX))) == NULL)
+                       fatal("agentx_index_integer_new");
+               break;
+       case AGENTX_INDEX_TYPE_NEW:
+               if ((applIndex = agentx_index_integer_new(application,
+                   AGENTX_OID(APPLINDEX))) == NULL)
+                       fatal("agentx_index_integer_new");
+               break;
+       case AGENTX_INDEX_TYPE_VALUE:
+               if ((applIndex = agentx_index_integer_value(application,
+                   AGENTX_OID(APPLINDEX),
+                   env->sc_agentx->applIndex)) == NULL)
+                       fatal("agentx_index_integer_new");
+               break;
+       case AGENTX_INDEX_TYPE_UNDEFINED:
+               fatalx("%s: How did I get here?", __func__);
+       }
+
+        if (agentx_object(application, AGENTX_OID(APPLNAME), &applIndex, 1, 0,
+           agentx_control_applName) == NULL ||
+            agentx_object(application, AGENTX_OID(APPLDIRECTORYNAME),
+           &applIndex, 1, 0, agentx_control_emptystring) == NULL ||
+            agentx_object(application, AGENTX_OID(APPLVERSION), &applIndex, 1,
+            0, agentx_control_applVersion) == NULL ||
+            agentx_object(application, AGENTX_OID(APPLUPTIME), &applIndex, 1, 
0,
+           agentx_control_applUptime) == NULL ||
+            agentx_object(application, AGENTX_OID(APPLOPERSTATUS), &applIndex,
+           1, 0, agentx_control_applOperStatus) == NULL ||
+            agentx_object(application, AGENTX_OID(APPLLASTCHANGE), &applIndex,
+           1, 0, agentx_control_applLastChange) == NULL ||
+            agentx_object(application, AGENTX_OID(APPLDESCRIPTION), &applIndex,
+           1, 0, agentx_control_applDescription) == NULL ||
+            agentx_object(application, AGENTX_OID(APPLURL), &applIndex, 1, 0,
+           agentx_control_applURL) == NULL ||
+           agentx_object(mta, AGENTX_OID(MTARECEIVEDMESSAGES), &applIndex, 1,
+            0, agentx_control_mtaReceivedMessages) == NULL ||
+           agentx_object(mta, AGENTX_OID(MTASTOREDMESSAGES), &applIndex, 1, 0,
+           agentx_control_mtaStoredMessages) == NULL ||
+           agentx_object(mta, AGENTX_OID(MTATRANSMITTEDMESSAGES), &applIndex,
+           1, 0, agentx_control_mtaTransmittedMessages) == NULL ||
+           agentx_object(mta, AGENTX_OID(MTALOOPSDETECTED), &applIndex, 1, 0,
+           agentx_control_mtaLoopsDetected) == NULL)
+                fatal("agentx_object");
+       
+}
+
+static void
+agentx_control_nofd(struct agentx *unused, void *cookie, int close)
+{
+       event_del(&rev);
+       agentx_control_tryconnect(-1, 0, NULL);
+}
+
+static void
+agentx_control_tryconnect(int fd, short event, void *cookie)
+{
+       m_create(p_parent, IMSG_AGENTX_GETFD, 0, 0, -1);
+       m_close(p_parent);
+}
+
+static void
+agentx_control_read(int fd, short event, void *cookie)
+{
+       agentx_read(sa);
+}
+
+void
+agentx_control_fdopen(int fd, int serrno)
+{
+       struct timeval timeout = {3, 0};
+
+       if (fd == -1) {
+               errno = serrno;
+               log_warn("Failed to connect to agentx master");
+               evtimer_set(&connev, agentx_control_tryconnect, NULL);
+               evtimer_add(&connev, &timeout);
+               return;
+       }
+
+       agentx_connect(sa, fd);
+
+       event_set(&rev, fd, EV_READ|EV_PERSIST, agentx_control_read, NULL);
+       event_add(&rev, NULL);
+}
+
+static void
+agentx_control_emptystring(struct agentx_varbind *vb)
+{
+       agentx_varbind_string(vb, "");
+}
+
+static void
+agentx_control_applName(struct agentx_varbind *vb)
+{
+       agentx_varbind_string(vb, "OpenSMTPd");
+}
+
+static void
+agentx_control_applVersion(struct agentx_varbind *vb)
+{
+       agentx_varbind_string(vb, SMTPD_VERSION);
+}
+
+static void
+agentx_control_applUptime(struct agentx_varbind *vb)
+{
+       agentx_varbind_timeticks(vb, (uint32_t) ((time(NULL) - digest.startup) 
* 100));
+}
+
+static void
+agentx_control_applOperStatus(struct agentx_varbind *vb)
+{
+       agentx_varbind_integer(vb, env->sc_flags & SMTPD_SMTP_PAUSED ? 2 : 1);
+}
+
+static void
+agentx_control_applLastChange(struct agentx_varbind *vb)
+{
+       /* I can't find this value, so just return a 0-value for now. */
+       agentx_varbind_timeticks(vb, 0);
+}
+
+static void
+agentx_control_applDescription(struct agentx_varbind *vb)
+{
+       agentx_varbind_string(vb, "OpenSMTPD is a FREE implementation of "
+           "the server-side SMTP protocol as defined by RFC 5321, with some "
+           "additional standard extensions. It allows ordinary machines to "
+           "exchange emails with other systems speaking the SMTP protocol.");
+}
+
+static void
+agentx_control_applURL(struct agentx_varbind *vb)
+{
+       agentx_varbind_string(vb, "");
+}
+
+static void
+agentx_control_mtaReceivedMessages(struct agentx_varbind *vb)
+{
+       agentx_varbind_counter32(vb, (uint32_t) digest.evp_enqueued);
+}
+
+static void
+agentx_control_mtaStoredMessages(struct agentx_varbind *vb)
+{
+       agentx_varbind_counter32(vb,
+           (uint32_t) (digest.evp_enqueued - digest.evp_dequeued));
+}
+
+static void
+agentx_control_mtaTransmittedMessages(struct agentx_varbind *vb)
+{
+       agentx_varbind_counter32(vb, digest.evp_dequeued);
+}
+
+static void
+agentx_control_mtaLoopsDetected(struct agentx_varbind *vb)
+{
+       agentx_varbind_counter32(vb, digest.dlv_loop);
+}
Index: control.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/control.c,v
retrieving revision 1.126
diff -u -p -r1.126 control.c
--- control.c   31 Dec 2020 08:27:15 -0000      1.126
+++ control.c   29 Apr 2021 05:22:14 -0000
@@ -73,7 +73,7 @@ extern const char *backend_stat;
 static uint64_t                        connid = 0;
 static struct tree             ctl_conns;
 static struct tree             ctl_count;
-static struct stat_digest      digest;
+struct stat_digest             digest;
 
 #define        CONTROL_FD_RESERVE              5
 #define        CONTROL_MAXCONN_PER_CLIENT      32
@@ -87,6 +87,7 @@ control_imsg(struct mproc *p, struct ims
        const char              *key;
        const void              *data;
        size_t                   sz;
+       int                      serrno;
 
        if (imsg == NULL) {
                if (p->proc != PROC_CLIENT)
@@ -157,6 +158,16 @@ control_imsg(struct mproc *p, struct ims
                if (stat_backend)
                        stat_backend->set(key, &val);
                return;
+       case IMSG_AGENTX_GETFD:
+               serrno = 0;
+               if (imsg->fd == -1) {
+                       m_msg(&m, imsg);
+                       m_get_int(&m, &serrno);
+                       m_end(&m);
+               }
+
+               agentx_control_fdopen(imsg->fd, serrno);
+               return;
        }
 
        errx(1, "control_imsg: unexpected %s imsg",
@@ -252,6 +263,9 @@ control(void)
        config_peer(PROC_CA);
 
        control_listen();
+
+       if (env->sc_agentx != NULL)
+               agentx_control();
 
        if (pledge("stdio unix recvfd sendfd", NULL) == -1)
                err(1, "pledge");
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/parse.y,v
retrieving revision 1.287
diff -u -p -r1.287 parse.y
--- parse.y     9 Apr 2021 16:43:43 -0000       1.287
+++ parse.y     29 Apr 2021 05:22:14 -0000
@@ -28,11 +28,13 @@
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
+#include <sys/un.h>
 
 #include <net/if.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
+#include <agentx.h>
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
@@ -177,9 +179,9 @@ typedef struct {
 
 %}
 
-%token ACTION ADMD ALIAS ANY ARROW AUTH AUTH_OPTIONAL
+%token ACTION ADMD AGENTX ALIAS ANY APPLINDEX ARROW AUTH AUTH_OPTIONAL
 %token BACKUP BOUNCE BYPASS
-%token CA CERT CHAIN CHROOT CIPHERS COMMIT COMPRESSION CONNECT
+%token CA CERT CHAIN CHROOT CIPHERS COMMIT COMPRESSION CONNECT CONTEXT
 %token DATA DATA_LINE DHE DISCONNECT DOMAIN
 %token EHLO ENABLE ENCRYPTION ERROR EXPAND_ONLY 
 %token FCRDNS FILTER FOR FORWARD_ONLY FROM
@@ -192,7 +194,7 @@ typedef struct {
 %token MAIL_FROM MAILDIR MASK_SRC MASQUERADE MATCH MAX_MESSAGE_SIZE 
MAX_DEFERRED MBOX MDA MTA MX
 %token NO_DSN NO_VERIFY NOOP
 %token ON
-%token PHASE PKI PORT PROC PROC_EXEC PROTOCOLS PROXY_V2
+%token PATH PHASE PKI PORT PROC PROC_EXEC PROTOCOLS PROXY_V2
 %token QUEUE QUIT
 %token RCPT_TO RDNS RECIPIENT RECEIVEDAUTH REGEX RELAY REJECT REPORT REWRITE 
RSET
 %token SCHEDULER SENDER SENDERS SMTP SMTP_IN SMTP_OUT SMTPS SOCKET SRC SRS 
SUB_ADDR_DELIM
@@ -228,6 +230,7 @@ grammar             : /* empty */
                | grammar dispatcher '\n'
                | grammar match '\n'
                | grammar filter '\n'
+               | grammar agentx '\n'
                | grammar error '\n'            { file->errors++; }
                ;
 
@@ -1978,6 +1981,82 @@ FILTER STRING CHAIN {
 }
 ;
 
+agentxopt      :
+CONTEXT STRING {
+       if (conf->sc_agentx->context != NULL) {
+               yyerror("redefinition of agentx context");
+               free($2);
+               YYERROR;
+       }
+       conf->sc_agentx->context = $2;
+}
+| PATH STRING {
+       if (strlen($2) >= sizeof(((struct sockaddr_un *)0)->sun_path)) {
+               yyerror("agentx path too large");
+               free($2);
+               YYERROR;
+       }
+       if ($2[0] != '/') {
+               yyerror("agentx path must be absolute");
+               free($2);
+               YYERROR;
+       }
+       if (conf->sc_agentx->path != NULL) {
+               yyerror("redefinition of agentx path");
+               free($2);
+               YYERROR;
+       }
+       conf->sc_agentx->path = $2;
+}
+| APPLINDEX STRING {
+       if (conf->sc_agentx->applIndexType != AGENTX_INDEX_TYPE_UNDEFINED) {
+               yyerror("redefinition of agentx applIndex");
+               YYERROR;
+       }
+
+       if (strcasecmp($2, "any") == 0)
+               conf->sc_agentx->applIndexType = AGENTX_INDEX_TYPE_ANY;
+       else if (strcasecmp($2, "new") == 0)
+               conf->sc_agentx->applIndexType = AGENTX_INDEX_TYPE_NEW;
+       else {
+               yyerror("invalid applIndex");
+               YYERROR;
+       }
+}
+| APPLINDEX NUMBER {
+       if (conf->sc_agentx->applIndexType != AGENTX_INDEX_TYPE_UNDEFINED) {
+               yyerror("redefinition of agentx applIndex");
+               YYERROR;
+       }
+       if ($2 > INT32_MAX) {
+               yyerror("agentx applIndex too large");
+               YYERROR;
+       }
+       if ($2 < 1) {
+               yyerror("agentx applIndex too small");
+               YYERROR;
+       }
+
+       conf->sc_agentx->applIndexType = AGENTX_INDEX_TYPE_VALUE;
+       conf->sc_agentx->applIndex = (uint32_t) $2;
+}
+;
+
+agentxopts     : /* empty */
+               | agentxopts agentxopt
+               ;
+
+agentx:
+AGENTX {
+       conf->sc_agentx = xcalloc(1, sizeof(*conf->sc_agentx));
+} agentxopts {
+       if (conf->sc_agentx->path == NULL)
+               conf->sc_agentx->path = AGENTX_MASTER_PATH;
+       if (conf->sc_agentx->applIndexType == AGENTX_INDEX_TYPE_UNDEFINED)
+               conf->sc_agentx->applIndexType = AGENTX_INDEX_TYPE_ANY;
+}
+;
+
 size           : NUMBER                {
                        if ($1 < 0) {
                                yyerror("invalid size: %" PRId64, $1);
@@ -2655,8 +2734,10 @@ lookup(char *s)
        static const struct keywords keywords[] = {
                { "action",             ACTION },
                { "admd",               ADMD },
+               { "agentx",             AGENTX },
                { "alias",              ALIAS },
                { "any",                ANY },
+               { "applIndex",          APPLINDEX },
                { "auth",               AUTH },
                { "auth-optional",      AUTH_OPTIONAL },
                { "backup",             BACKUP },
@@ -2670,6 +2751,7 @@ lookup(char *s)
                { "commit",             COMMIT },
                { "compression",        COMPRESSION },
                { "connect",            CONNECT },
+               { "context",            CONTEXT },
                { "data",               DATA },
                { "data-line",          DATA_LINE },
                { "dhe",                DHE },
@@ -2713,6 +2795,7 @@ lookup(char *s)
                { "no-verify",          NO_VERIFY },
                { "noop",               NOOP },
                { "on",                 ON },
+               { "path",               PATH },
                { "phase",              PHASE },
                { "pki",                PKI },
                { "port",               PORT },
Index: smtpd.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd.c,v
retrieving revision 1.338
diff -u -p -r1.338 smtpd.c
--- smtpd.c     21 Apr 2021 07:54:10 -0000      1.338
+++ smtpd.c     29 Apr 2021 05:22:14 -0000
@@ -25,6 +25,7 @@
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <sys/uio.h>
+#include <sys/un.h>
 #include <sys/mman.h>
 
 #include <bsd_auth.h>
@@ -70,6 +71,7 @@ static void parent_send_config_lka(void)
 static void parent_send_config_dispatcher(void);
 static void parent_send_config_ca(void);
 static void parent_sig_handler(int, short, void *);
+static int parent_open_agentx(void);
 static void forkmda(struct mproc *, uint64_t, struct deliver *);
 static int parent_forward_open(char *, char *, uid_t, gid_t);
 static struct child *child_add(pid_t, int, const char *);
@@ -168,7 +170,7 @@ parent_imsg(struct mproc *p, struct imsg
        uint64_t                 reqid;
        size_t                   sz;
        void                    *i;
-       int                      fd, n, v, ret;
+       int                      fd, n, v, ret, serrno;
 
        if (imsg == NULL)
                fatalx("process %s socket closed", p->name);
@@ -268,6 +270,16 @@ parent_imsg(struct mproc *p, struct imsg
                m_add_string(p_lka, procname);
                m_close(p_lka);
                return;
+       case IMSG_AGENTX_GETFD:
+               fd = parent_open_agentx();
+               if (fd == -1)
+                       serrno = errno;
+
+               m_create(p_control, IMSG_AGENTX_GETFD, 0, 0, fd);
+               if (fd == -1)
+                       m_add_int(p_control, serrno);
+               m_close(p_control);
+               return;
        }
 
        errx(1, "parent_imsg: unexpected %s imsg from %s",
@@ -474,6 +486,29 @@ parent_sig_handler(int sig, short event,
        }
 }
 
+static int
+parent_open_agentx(void)
+{
+       int fd;
+       struct sockaddr_un sun;
+       int serrno;
+
+       sun.sun_len = sizeof(sun);
+       sun.sun_family = AF_UNIX;
+       strlcpy(sun.sun_path, env->sc_agentx->path, sizeof(sun.sun_path));
+
+       if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+               return -1;
+
+       if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
+               serrno = errno;
+               close(fd);
+               errno = serrno;
+               return -1;
+       }
+       return fd;
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -639,6 +674,7 @@ main(int argc, char *argv[])
                errx(1, "need root privileges");
 
        log_init(foreground_log, LOG_MAIL);
+       log_setverbose(tracing & TRACE_DEBUG ? 2: 1);
        log_trace_verbose(tracing);
        load_pki_tree();
        load_pki_keys();
@@ -2122,6 +2158,8 @@ imsg_to_str(int type)
        CASE(IMSG_CA_RSA_PRIVENC);
        CASE(IMSG_CA_RSA_PRIVDEC);
        CASE(IMSG_CA_ECDSA_SIGN);
+
+       CASE(IMSG_AGENTX_GETFD);
        default:
                (void)snprintf(buf, sizeof(buf), "IMSG_??? (%d)", type);
 
Index: smtpd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd.conf.5,v
retrieving revision 1.260
diff -u -p -r1.260 smtpd.conf.5
--- smtpd.conf.5        9 Apr 2021 16:43:43 -0000       1.260
+++ smtpd.conf.5        29 Apr 2021 05:22:14 -0000
@@ -338,6 +338,33 @@ The Administrative Management Domain thi
 The authservid will be forwarded to filters using it to identify or mark
 authentication-results headers.
 If omitted it defaults to the server name.
+.It Ic agentx Oo Cm applIndex Ar index Oc Oo Cm context Ar context Oc Op Cm 
path Ar path
+Export NETWORK-SERVICES-MIB and MTA-MIB metrics via an agentx compatible
+.Pq snmp
+daemon by connecting to
+.Ar path .
+Metrics can be found under the application
+.Pq mib-2.27
+and mta subtree
+.Pq mib-2.28 .
+If
+.Ar path
+is omitted it will default to
+.Pa /var/agentx/master .
+The index on the applicationTable and mtaTable can be controlled via
+.Cm applIndex .
+For the first available index it can be set to
+.Cm any ,
+for a new unused entry it can be set to
+.Cm new ,
+and if a fixed position is desired it can be set to a number between 1 and
+2,147,483,647.
+If an index collision occurs because of a fixed position the metrics will not 
be
+exported.
+.Cm applIndex
+defaults to any.
+.Ar Context
+is the SNMPv3 context and can usually be omitted.
 .It Ic bounce Cm warn-interval Ar delay Op , Ar delay ...
 Send warning messages to the envelope sender when temporary delivery
 failures cause a message to remain in the queue for longer than
Index: smtpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd.h,v
retrieving revision 1.668
diff -u -p -r1.668 smtpd.h
--- smtpd.h     21 Apr 2021 07:54:10 -0000      1.668
+++ smtpd.h     29 Apr 2021 05:22:14 -0000
@@ -157,7 +157,7 @@ union lookup {
  * Bump IMSG_VERSION whenever a change is made to enum imsg_type.
  * This will ensure that we can never use a wrong version of smtpctl with 
smtpd.
  */
-#define        IMSG_VERSION            16
+#define        IMSG_VERSION            17
 
 enum imsg_type {
        IMSG_NONE,
@@ -327,6 +327,8 @@ enum imsg_type {
        IMSG_CA_RSA_PRIVENC,
        IMSG_CA_RSA_PRIVDEC,
        IMSG_CA_ECDSA_SIGN,
+
+       IMSG_AGENTX_GETFD,
 };
 
 enum smtp_proc_type {
@@ -622,6 +624,8 @@ struct smtpd {
        int                                     sc_srs_ttl;
 
        char                                   *sc_admd;
+
+       struct smtp_agentx                     *sc_agentx;
 };
 
 #define        TRACE_DEBUG     0x0001
@@ -858,6 +862,20 @@ struct mta_envelope {
        char                             status[LINE_MAX];
 };
 
+enum agentx_index_type {
+       AGENTX_INDEX_TYPE_UNDEFINED,
+       AGENTX_INDEX_TYPE_ANY,
+       AGENTX_INDEX_TYPE_NEW,
+       AGENTX_INDEX_TYPE_VALUE,
+};
+
+struct smtp_agentx {
+       const char                      *path;
+       const char                      *context;
+       enum agentx_index_type           applIndexType;
+       uint32_t                         applIndex;
+};
+
 struct mta_task {
        TAILQ_ENTRY(mta_task)            entry;
        struct mta_relay                *relay;
@@ -1298,6 +1316,9 @@ void config_peer(enum smtp_proc_type);
 int control(void);
 int control_create_socket(void);
 
+/* agentx_control.c */
+void agentx_control(void);
+void agentx_control_fdopen(int, int);
 
 /* crypto.c */
 int    crypto_setup(const char *, size_t);
Index: smtpd/Makefile
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd/Makefile,v
retrieving revision 1.113
diff -u -p -r1.113 Makefile
--- smtpd/Makefile      21 Apr 2021 07:54:10 -0000      1.113
+++ smtpd/Makefile      29 Apr 2021 05:22:14 -0000
@@ -4,7 +4,8 @@
 
 PROG=          smtpd
 
-SRCS=  aliases.c
+SRCS=  agentx_control.c
+SRCS+= aliases.c
 SRCS+= bounce.c
 SRCS+= ca.c
 SRCS+= compress_backend.c
@@ -79,8 +80,8 @@ SRCS+=                stat_ramstat.c
 MAN=           sendmail.8 smtpd.8 smtpd.conf.5 table.5
 BINDIR=                /usr/sbin
 
-LDADD+=                -levent -lutil -ltls -lssl -lcrypto -lz
-DPADD+=                ${LIBEVENT} ${LIBUTIL} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO} 
${LIBZ}
+LDADD+=                -levent -lutil -ltls -lssl -lcrypto -lz -lagentx
+DPADD+=                ${LIBEVENT} ${LIBUTIL} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO} 
${LIBZ} ${LIBAGENTX}
 
 CFLAGS+=       -fstack-protector-all
 CFLAGS+=       -I${.CURDIR}/..



Reply via email to