如何实现socat同时转发输入至TCP连接与PHP脚本(Postfix场景)?
实现Postfix内容过滤器:socat双向转发+单向输入到PHP脚本
要实现你需要的功能,核心是让socat把接收到的输入(从Postfix来的邮件数据)复制一份给PHP脚本,同时保持原有与10025端口的双向通信。我们可以通过shell的tee命令结合进程替换,配合socat的SYSTEM选项来实现,具体方案如下:
最终命令
socat tcp-listen:10026,reuseaddr,fork SYSTEM:"bash -c 'tee >(php /absolute/path/to/your/filter-script.php) | socat - tcp:localhost:10025,copyaddr'"
命令拆解与工作流程
让我一步步解释这个命令的逻辑:
- 外层socat:监听10026端口,
reuseaddr允许端口快速复用,fork为每个新连接创建独立进程处理,避免阻塞。 - SYSTEM选项:把每个连接的输入传递给bash命令处理,同时把bash命令的输出回传给客户端(Postfix)。
- tee + 进程替换:
tee会把接收到的邮件数据复制成两份:一份通过>(...)进程替换传递给你的PHP脚本;另一份通过管道传给内层socat。- 进程替换
>(php ...)需要bash支持,所以我们显式指定bash -c来执行命令。
- 内层socat:把收到的数据转发到10025端口,同时把10025返回的响应(比如SMTP状态码)回传,这样就完整保留了原有的双向通信能力。
- copyaddr选项:让内层socat保留客户端的源地址,对Postfix的日志和后续处理更友好。
PHP脚本示例
你的PHP脚本需要读取标准输入(也就是socat转发过来的邮件内容),这里给一个简单的日志记录示例:
<?php // 读取完整的邮件内容 $email = file_get_contents('php://stdin'); // 这里添加你的过滤/处理逻辑:比如检查邮件主题、内容,调用API,记录审计日志等 $logEntry = sprintf("[%s] Received email:\n%s\n\n", date('Y-m-d H:i:s'), $email); file_put_contents('/var/log/postfix-content-filter.log', $logEntry, FILE_APPEND); // 脚本的输出会被自动丢弃,不需要返回内容给socat ?>
关键注意事项
- 权限问题:确保运行socat的用户(通常是postfix或root)有执行PHP脚本、写入日志文件的权限。
- 性能考量:如果PHP脚本处理耗时较长,可能会影响邮件投递速度。如果需要处理大量邮件,建议把输入写入异步队列(比如Redis),用单独的进程处理,避免阻塞转发流程。
- 测试验证:可以用
telnet localhost 10026发送测试SMTP数据,检查10025端口是否收到数据,同时查看PHP脚本的日志是否有记录,并且能正常收到10025的响应。 - 容错性:即使PHP脚本崩溃或异常,
tee依然会把数据转发给内层socat,不会影响Postfix与10025的正常通信,保证核心转发功能不受影响。
内容的提问来源于stack exchange,提问作者jchook
相关产品推荐
相关产品推荐

