smtp-source without installing Postfix: Extract load-testing tools from the RPM
smtp-source and smtp-sink are part of Postfix, but they also run without an installed mail server. Learn how to extract the two tools from the package on RHEL, why running them from /tmp can fail because of the noexec mount option, and which libraries need to be included.
For SMTP load tests, smtp-source is a good choice: the tool opens parallel sessions, keeps them open across multiple messages, and therefore models the connection behavior of a bulk sender far more realistically than testing tools that establish a new connection for each email. Its counterpart, smtp-sink, accepts emails and discards them without delivering anything. Both are included with Postfix.
That is precisely the problem: Postfix is often not installed on the system from which you want to test. Installation is also undesirable on a mail gateway appliance because an additional Postfix installation comes with its own configuration under /etc/postfix and a system service that, in the worst case, occupies port 25 and blocks the actual mail system. There is also the question of what vendor support thinks of packages installed afterward on its appliance.
However, both tools can also be used without installation: download the RPM, extract the binaries along with the libraries, and you are done. The path to this has two peculiarities, which this article demonstrates on a RHEL 8 system. You do not need root privileges, only access to the package sources.
Is smtp-source already present?
First, check whether the tool might already be on the system after all. Depending on the distribution, smtp-source is located outside the normal PATH:
command -v smtp-source || \
ls /usr/sbin/smtp-source /usr/lib/postfix/sbin/smtp-source 2>/dev/null
If the output remains empty, the associated package is also missing. On RPM systems, confirm this and check whether the repositories offer Postfix at the same time:
rpm -qa | grep -i postfix
yum list available postfix
On the test system, Postfix was not installed, but the BaseOS repository offered postfix-3.5.8-8.el8_10. This clears the way: the package can be downloaded without installing it.
Download only the RPM
yum download (from the dnf-plugins-core plugin package, usually present on RHEL 8) downloads a package into the current directory without installing it. This works without root privileges as long as the destination directory is writable:
cd /tmp && yum download postfix
If yum reports No such command: download, the plugin is missing. With root privileges, you can achieve the same result through the installation command with --downloadonly:
sudo yum install --downloadonly --downloaddir=/tmp postfix
Without either option, the remaining workaround is to use a second system with the same RHEL version: download the RPM there and copy it to the target system with scp.
Extract binaries and libraries
rpm2cpio converts the RPM into a cpio archive stream, from which cpio selectively extracts individual paths. In addition to the two binaries, you also need the Postfix libraries because on RHEL the tools are dynamically linked against libpostfix-*.so:
cd /tmp && rpm2cpio postfix-*.rpm | \
cpio -idmv ./usr/sbin/smtp-source ./usr/sbin/smtp-sink \
'./usr/lib64/postfix/*'
The files are then located below /tmp/usr/.
Problem 1: /tmp is mounted with noexec
The obvious approach of starting directly from /tmp fails on hardened systems:
bash: /tmp/usr/sbin/smtp-sink: Permission denied
[1]+ Exit 126
Exit code 126 despite the execute bit being set correctly is the typical sign of a filesystem mounted with the noexec option. The kernel then denies every attempt to execute a program from that filesystem, regardless of file permissions. You can check this directly:
mount | grep ' /tmp '
The solution is to copy the binaries and libraries to a directory on a filesystem that permits execution, such as your home directory:
mkdir -p ~/bin && \
cp /tmp/usr/sbin/smtp-source /tmp/usr/sbin/smtp-sink \
/tmp/usr/lib64/postfix/libpostfix-*.so ~/bin/ && \
chmod +x ~/bin/smtp-source ~/bin/smtp-sink
Note that noexec also affects the loading of shared libraries. Therefore, it is not enough to move only the binaries and leave the libraries in /tmp.
Problem 2: the library path
Without further instructions, the dynamic linker looks for the Postfix libraries under /usr/lib64/postfix, where they are absent because Postfix is not installed:
smtp-sink: error while loading shared libraries: libpostfix-global.so:
cannot open shared object file: No such file or directory
LD_LIBRARY_PATH adds your own directory to the linker’s search path. Prefix every invocation with the variable:
LD_LIBRARY_PATH=~/bin ~/bin/smtp-source ...
With ldd ~/bin/smtp-source, you can check in advance whether all dependencies can be resolved. Apart from the Postfix libraries, the tools depend only on standard system libraries.
Loopback functional test
You can verify that everything works without sending a single real email: smtp-sink listens as a disposable receiver on a high port, while smtp-source delivers to it. All traffic remains on localhost.
LD_LIBRARY_PATH=~/bin ~/bin/smtp-sink -v 127.0.0.1:2525 100 &
LD_LIBRARY_PATH=~/bin ~/bin/smtp-source -s 2 -m 10 -l 5120 \
-f test@example.com -t test@example.com 127.0.0.1:2525
On success, smtp-source produces no output, while smtp-sink outputs the complete SMTP dialog from HELO through QUIT for every message. Then stop the background process and remove the leftovers from /tmp:
kill %1
rm -rf /tmp/usr /tmp/postfix-*.rpm
Notes for the actual load test
For reliable throughput measurements, place the load generator on a separate machine in the same network segment, not on the test target itself. If smtp-source runs on the gateway being tested, the generator and mail system compete for CPU and I/O, and the measurement reflects that competition rather than actual capacity. Locally on the target system, the extracted tool is primarily suitable for functional tests of the rule set and initial plausibility checks.
As soon as the test targets the actual port 25, the emails are real and pass through the gateway’s rule set, potentially being delivered depending on the configuration. Therefore, use recipient addresses that terminate in a controlled manner: a dedicated test mailbox, a rule that discards the test senders, or a discard domain designated for this purpose by the provider. Production addresses do not belong in a load test.
The procedure described is suitable beyond the two SMTP tools for any command-line program that comes in a package whose installation on the target system is not an option. The combination of yum download, rpm2cpio, and an executable directory in the home directory is the same on every RPM system.
Comments
Comments are loaded from GitHub / Giscus.