OpenBSD – OpenSMTPD table protocol changes, now with the backstory

https://www.undeadly.org/cgi?action=article;sid=20240503110540

Contributed by Peter N. M. Hansteen on 2024-05-03 from the tables, we deliver dept.

Regular readers will be aware that OpenBSD ships with its own mail server implementation, OpenSMTPD, in its base system.

In a recent message to the tech@ mailing list, Omar Polo (op@) asked for comments or oks for a patches implementing a change of table protocols. A little later, Gilles Chehade (gilles@) posted to the [email protected] mailing list with the backstory for this change.

The message follows in full below (apparently the otherwise fine marc.info archive site no longer archives the list):

Date: Fri, 03 May 2024 08:22:03 +0000
From: [email protected]
To: [email protected]
Subject: smtpd: change the table protocol
Hello,
This is a copy of a mail I sent to OpenBSD hackers a few days ago so you are aware of work
being done on OpenSMTPD by Omar Polo.
~~~
TL;DR: proposal to change table backends wire protocol to one that's closer to filters, it
       has proven to work for years now, comes with many benefits and it is a very trivial
       change that we can pull in a handful of hours:
       https://tmp.omarpolo.com/smtpd-tables.7.html
Longer mail with historical context.
A long time ago, OpenSMTPD shipped with two table backends for its table API: file and db.
Then we started seeing a need for ldap and SQLite, so we wrote backends for them and since
we had aldap.[ch] and SQLite in base this wasn't really a problem.
Then we started seeing a need for mySQL and postgreSQL which became problematic because we
didn't want OpenSMTPD to ship with backends that couldn't be built in base out of the box,
but also because if we had to fix a bug in table_mysql, it meant we had to do an OpenSMTPD
release to provide the fix for portable users.
To solve this, we introduced the "procexec" API, a mean for OpenSMTPD to spawn tables in a
separate process with socketpairs in place to perform lookups and obtain results via imsg.
This made it possible to release table backends separately as standalone programs, without
limitations to their dependencies and without requiring releases to be synchronised. Table
backends were releases as part of OpenSMTPD-extras, and we could do several releases of it
in the timespan of a single OpenSMTPD release.
Later, we did the same for filters, it turned out to be much more complex and we failed so
hard our first attempts that we reverted and waited two years to make a new proposal. That
new proposal replaced imsg with an stdio line-based protocol which was much simpler for us
to implement in the daemon and it had the benefit that users could easily interact with it
to handle use-cases we didn't care about using the languages they wanted. I have seen some
filters in awk, rust, C, golang, Perl, Python, ... users are happy with the simple API and
we didn't have to handle exotic use-cases in the daemon, which is good.
Recently there's been a few contributions to table-ldap in OpenSMTPD-extras, the first one
in years, and I think that the fact table backends still use "procexec" is a reason why we
can't rely on the community to contribute: you can't just read a line, parse it and reply,
instead you need to know how imsg works, you need to understand non-blocking async I/O and
you can't start a table backend of your own in a preferred language... so unless one of us
does the work, it stales (I wrote table_ldap ... I don't even use or care for ldap).
A while back I told eric@ we could switch tables to a filter-like protocol, he agreed, but
we never got to do it. Recently, as op@ began contributing more and more, I told him about
that idea again and my 3-steps plan to switch to it:
1- implement a table_stdio backend which translates imsg protocol to stdio protocol
2- convert all table backends to the new protocol
3- move the table_stdio code in smtpd so we no longer need table_stdio
These are all trivial changes and op@ actually already implemented 1- and 2-, we'd like to
start the work on 3- considering that all of this project is easy: we're changing the wire
protocol but the table API remains 100% the same from OpenSMTPD and filters perspective.
The new table protocol is identical to the smtpd-filters(7) protocol (draft by op@), it is
readable in HTML at the following link and I've included the man page at end of mail:
    https://tmp.omarpolo.com/smtpd-tables.7.html
The operations are exactly the same as with imsg, and since the imsg protocol already made
results available as serialised strings, we already parse them from string to structs, and
we'll re-use the same code. The change is mainly in not encapsulating them in imsg packets.
~~~
Note that we're past this as of today:
1- table_stdio was implemented as a PoC:
  - https://github.com/OpenSMTPD/table-stdio
2- all table backends from OpenSMTPD-extras were converted to the new interface:
  - https://github.com/OpenSMTPD/table-socketmap
  - https://github.com/OpenSMTPD/table-passwd
  - https://github.com/OpenSMTPD/table-ldap
  - https://github.com/OpenSMTPD/table-sqlite
  - https://github.com/OpenSMTPD/table-redis
  - https://github.com/OpenSMTPD/table-postgres
  - https://github.com/OpenSMTPD/table-mysql
3- Omar has sent a mail to tech@ with the diff to integrate protocol in smtpd:
  - https://marc.info/?l=openbsd-tech&m=171439783225288&w=2
There you go, now you know !
{
"by": "peter_hansteen",
"descendants": 0,
"id": 40246307,
"score": 1,
"time": 1714734372,
"title": "OpenBSD – OpenSMTPD table protocol changes, now with the backstory",
"type": "story",
"url": "https://www.undeadly.org/cgi?action=article;sid=20240503110540"
}
{
"author": null,
"date": "2024-05-03T09:05:35.000Z",
"description": null,
"image": "https://www.undeadly.org/images/MangaRamblo_25_x.png",
"logo": null,
"publisher": "OpenBSD Journal",
"title": "OpenSMTPD table protocol changes, now with the backstory",
"url": "https://www.undeadly.org/cgi?action=article;sid=20240503110540"
}
{
"url": "https://www.undeadly.org/cgi?action=article%3Bsid%3D20240503110540",
"title": "OpenSMTPD table protocol changes, now with the backstory",
"description": "Contributed by Peter N. M. Hansteen on 2024-05-03 from the tables, we deliver dept. Regular readers will be aware that OpenBSD ships with its own mail server implementation, OpenSMTPD, in its base...",
"links": [
"https://www.undeadly.org/cgi?action=article%3Bsid%3D20240503110540"
],
"image": "",
"content": "<div>\n<p>Contributed by\n<a target=\"_blank\" href=\"http://bsdly.blogspot.com/\">Peter N. M. Hansteen</a>\non 2024-05-03\nfrom the tables, we deliver dept.</p><p>\nRegular readers will be aware that <a target=\"_blank\" href=\"https://www.openbsd.org/\">OpenBSD</a> ships with its own mail server implementation, <a target=\"_blank\" href=\"https://www.opensmtpd.org/\">OpenSMTPD</a>, in its base system.\r\n</p><p>\r\nIn a recent <a target=\"_blank\" href=\"https://marc.info/?l=openbsd-tech&amp;m=171439783225288&amp;w=2\">message</a> to the <code>tech@</code> mailing list, Omar Polo (<code>op@</code>) asked for comments or <code>ok</code>s for a patches implementing a change of table protocols. A little later, Gilles Chehade (<code>gilles@</code>) posted to the <code>[email protected]</code> mailing list with the backstory for this change.\r\n</p><p>\r\nThe message follows in full below (apparently the otherwise fine <a target=\"_blank\" href=\"https://marc.info/\">marc.info</a> archive site no longer archives the list):\r\n</p><blockquote><pre>\r\nDate: Fri, 03 May 2024 08:22:03 +0000\r\nFrom: [email protected]\r\nTo: [email protected]\r\nSubject: smtpd: change the table protocol\nHello,\nThis is a copy of a mail I sent to OpenBSD hackers a few days ago so you are aware of work\r\nbeing done on OpenSMTPD by Omar Polo.\n~~~\n<abbr>TL;DR</abbr>: proposal to change table backends wire protocol to one that's closer to filters, it\r\n has proven to work for years now, comes with many benefits and it is a very trivial\r\n change that we can pull in a handful of hours:\r\n <a target=\"_blank\" href=\"https://tmp.omarpolo.com/smtpd-tables.7.html\">https://tmp.omarpolo.com/smtpd-tables.7.html</a>\r\n</pre></blockquote>\n<blockquote><pre>\r\nLonger mail with historical context.\nA long time ago, OpenSMTPD shipped with two table backends for its table <abbr>API</abbr>: file and <abbr>db</abbr>.\nThen we started seeing a need for <abbr>ldap</abbr> and SQLite, so we wrote backends for them and since\r\nwe had aldap.[ch] and SQLite in base this wasn't really a problem.\nThen we started seeing a need for mySQL and postgreSQL which became problematic because we\r\ndidn't want OpenSMTPD to ship with backends that couldn't be built in base out of the box,\r\nbut also because if we had to fix a bug in table_mysql, it meant we had to do an OpenSMTPD\r\nrelease to provide the fix for portable users.\nTo solve this, we introduced the \"procexec\" <abbr>API</abbr>, a mean for OpenSMTPD to spawn tables in a\r\nseparate process with socketpairs in place to perform lookups and obtain results via imsg.\r\nThis made it possible to release table backends separately as standalone programs, without\r\nlimitations to their dependencies and without requiring releases to be synchronised. Table\r\nbackends were releases as part of OpenSMTPD-extras, and we could do several releases of it\r\nin the timespan of a single OpenSMTPD release.\nLater, we did the same for filters, it turned out to be much more complex and we failed so\r\nhard our first attempts that we reverted and waited two years to make a new proposal. That\r\nnew proposal replaced imsg with an stdio line-based protocol which was much simpler for us\r\nto implement in the daemon and it had the benefit that users could easily interact with it\r\nto handle use-cases we didn't care about using the languages they wanted. I have seen some\r\nfilters in awk, rust, C, golang, Perl, Python, ... users are happy with the simple <abbr>API</abbr> and\r\nwe didn't have to handle exotic use-cases in the daemon, which is good.\nRecently there's been a few contributions to table-ldap in OpenSMTPD-extras, the first one\r\nin years, and I think that the fact table backends still use \"procexec\" is a reason why we\r\ncan't rely on the community to contribute: you can't just read a line, parse it and reply,\r\ninstead you need to know how imsg works, you need to understand non-blocking async <abbr>I/O</abbr> and\r\nyou can't start a table backend of your own in a preferred language... so unless one of us\r\ndoes the work, it stales (I wrote table_ldap ... I don't even use or care for <abbr>ldap</abbr>).\nA while back I told eric@ we could switch tables to a filter-like protocol, he agreed, but\r\nwe never got to do it. Recently, as op@ began contributing more and more, I told him about\r\nthat idea again and my 3-steps plan to switch to it:\n1- implement a table_stdio backend which translates imsg protocol to stdio protocol\r\n2- convert all table backends to the new protocol\r\n3- move the table_stdio code in smtpd so we no longer need table_stdio\nThese are all trivial changes and op@ actually already implemented 1- and 2-, we'd like to\r\nstart the work on 3- considering that all of this project is easy: we're changing the wire\r\nprotocol but the table API remains 100% the same from OpenSMTPD and filters perspective.\nThe new table protocol is identical to the <a target=\"_blank\" href=\"https://man.openbsd.org/smtpd-filters\">smtpd-filters(7)</a> protocol (draft by op@), it is\r\nreadable in HTML at the following link and I've included the man page at end of mail:\n <a target=\"_blank\" href=\"https://tmp.omarpolo.com/smtpd-tables.7.html\">https://tmp.omarpolo.com/smtpd-tables.7.html</a>\nThe operations are exactly the same as with imsg, and since the imsg protocol already made\r\nresults available as serialised strings, we already parse them from string to structs, and\r\nwe'll re-use the same code. The change is mainly in not encapsulating them in imsg packets.\n~~~\nNote that we're past this as of today:\n1- table_stdio was implemented as a <abbr>PoC</abbr>:\r\n - <a target=\"_blank\" href=\"https://github.com/OpenSMTPD/table-stdio\">https://github.com/OpenSMTPD/table-stdio</a>\n2- all table backends from OpenSMTPD-extras were converted to the new interface:\r\n - <a target=\"_blank\" href=\"https://github.com/OpenSMTPD/table-socketmap\">https://github.com/OpenSMTPD/table-socketmap</a>\r\n - <a target=\"_blank\" href=\"https://github.com/OpenSMTPD/table-passwd\">https://github.com/OpenSMTPD/table-passwd</a>\r\n - <a target=\"_blank\" href=\"https://github.com/OpenSMTPD/table-ldap\">https://github.com/OpenSMTPD/table-ldap</a>\r\n - <a target=\"_blank\" href=\"https://github.com/OpenSMTPD/table-sqlite\">https://github.com/OpenSMTPD/table-sqlite</a>\r\n - <a target=\"_blank\" href=\"https://github.com/OpenSMTPD/table-redis\">https://github.com/OpenSMTPD/table-redis</a>\r\n - <a target=\"_blank\" href=\"https://github.com/OpenSMTPD/table-postgres\">https://github.com/OpenSMTPD/table-postgres</a>\r\n - <a target=\"_blank\" href=\"https://github.com/OpenSMTPD/table-mysql\">https://github.com/OpenSMTPD/table-mysql</a>\n3- Omar has sent a mail to tech@ with the <abbr>diff</abbr> to integrate protocol in smtpd:\r\n - <a target=\"_blank\" href=\"https://marc.info/?l=openbsd-tech&amp;m=171439783225288&amp;w=2\">https://marc.info/?l=openbsd-tech&amp;m=171439783225288&amp;w=2</a>\nThere you go, now you know !\r\n</pre></blockquote>\n</div>",
"author": "",
"favicon": "",
"source": "undeadly.org",
"published": "",
"ttr": 173,
"type": ""
}