![Postfix - 出站 SMTP 流量流出错误接口](https://linux22.com/image/758903/Postfix%20-%20%E5%87%BA%E7%AB%99%20SMTP%20%E6%B5%81%E9%87%8F%E6%B5%81%E5%87%BA%E9%94%99%E8%AF%AF%E6%8E%A5%E5%8F%A3.png)
我有一台 Postfix 服务器,在我进行一些网络更改之前,它一直运行良好(入站和出站)。我添加了一个接口(用于第二个公共 IP 地址,通过 VPN 隧道。我打算运行多个 Postfix 服务器,以支持不同 IP 地址上的不同域、证书等。)
更改后,postfix 可以正常接收入站邮件,但出站流量从错误的接口流出,因此无法投递邮件(该接口上的端口 25 被阻止)。 mail.log
向任何外部 SMTP 服务器显示“连接被拒绝”或“网络不可达”。
错误消息示例来自mail.log
:
Oct 18 17:13:10 vox postfix/smtp[22694]: connect to mx-asp.jvlicenses.com[198.199.107.159]:25: Connection timed out
Oct 18 17:13:10 vox postfix/smtp[22694]: 39DCBA6227: to=<[email protected]>, relay=none, delay=1096, delays=1066/0.02/30/0, dsn=4.4.1, status=deferred (connect to mx-asp.jvlicenses.com[198.199.107.159]:25: Connection timed out)
我正在使用smtp_bind_address参数 inmaster.cf
指定 Postfix 应使用的源地址。我也尝试过使用inet_addresses
in master.cf
,但似乎也不起作用。流量总是从默认网关发出,而不是所需的接口。(当所有这些都正常工作时,我认为默认路由可能是所需的路由,但我记不清了。)
我想要的是表示 postfix 使用源 IP 发送邮件10.8.0.8
,根据我的路由规则,源 IP 应该从接口发出tun45
。但据我所知,postfix 使用192.168.122.185
设备上的IP 发送邮件enp1s0
——这是主机上的默认路由。
3.4.14
我在 Debian 上运行 postfix 版本4.19.118-2 (2020-04-24)
。
接下来是一些额外的配置细节,以及我用来测试的步骤。
Postfix 绑定到10.8.0.8
,如netstat所示:
# netstat -ntlp|grep master
tcp 0 0 10.8.0.8:25 0.0.0.0:* LISTEN 22293/master
tcp 0 0 10.8.0.8:587 0.0.0.0:* LISTEN 22293/master
tcp 0 0 10.8.0.8:465 0.0.0.0:* LISTEN 22293/master
该地址是tun45
主机上的设备:
# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:4b:2c:5b brd ff:ff:ff:ff:ff:ff
inet 192.168.122.185/24 brd 192.168.122.255 scope global dynamic noprefixroute enp1s0
valid_lft 2672sec preferred_lft 2672sec
inet6 fe80::5054:ff:fe4b:2c5b/64 scope link noprefixroute
valid_lft forever preferred_lft forever
9: tun45: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
link/none
inet 10.8.0.8/24 brd 10.8.0.255 scope global tun45
valid_lft forever preferred_lft forever
inet6 fe80::e401:70cf:ba68:88b1/64 scope link stable-privacy
valid_lft forever preferred_lft forever
11: tun66: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
link/none
inet 10.8.0.7/24 brd 10.8.0.255 scope global tun66
valid_lft forever preferred_lft forever
inet6 fe80::41d:c2e1:9428:5630/64 scope link stable-privacy
valid_lft forever preferred_lft forever
从 IP 路由到任何外部地址(在本例中为 jvlicenses.com 的 MTA)10.8.0.8
都应通过设备tun45
:
# ip route get 198.199.107.159 from 10.8.0.8
198.199.107.159 from 10.8.0.8 dev tun45 table t1 uid 0
cache
路由表t1
只有一个条目:
# ip route show table t1
default dev tun45 scope link
我可以使用 netcat 连接到外部服务器 post 25,使用相同的源地址:
# nc -s 10.8.0.8 198.199.107.159 25
220 mx-asp.jvlicenses.com ESMTP Postfix
QUIT
221 2.0.0 Bye
tcpdump 显示 netcat 连接具有正确的源地址等:
# tcpdump -ni tun45 dst port 25
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tun45, link-type RAW (Raw IP), capture size 262144 bytes
16:27:02.522570 IP 10.8.0.8.42427 > 198.199.107.159.25: Flags [S], seq 4118387792, win 64240, options [mss 1460,sackOK,TS val 2496426612 ecr 0,nop,wscale 8], length 0
16:27:02.689912 IP 10.8.0.8.42427 > 198.199.107.159.25: Flags [.], ack 1806817019, win 251, options [nop,nop,TS val 2496426779 ecr 75983973], length 0
16:27:02.857545 IP 10.8.0.8.42427 > 198.199.107.159.25: Flags [.], ack 42, win 251, options [nop,nop,TS val 2496426947 ecr 75984142], length 0
16:27:14.393645 IP 10.8.0.8.42427 > 198.199.107.159.25: Flags [P.], seq 0:5, ack 42, win 251, options [nop,nop,TS val 2496438483 ecr 75984142], length 5: SMTP: QUIT
16:27:14.650912 IP 10.8.0.8.42427 > 198.199.107.159.25: Flags [.], ack 57, win 251, options [nop,nop,TS val 2496438740 ecr 75995841], length 0
16:27:14.651089 IP 10.8.0.8.42427 > 198.199.107.159.25: Flags [F.], seq 5, ack 58, win 251, options [nop,nop,TS val 2496438740 ecr 75995842], length 0
但是当我向该服务器发送电子邮件时,tun45 上没有流量。相反,我看到它从设备上的默认路由出去enp1s0
:
# tcpdump -n dst port 25 -vv
tcpdump: listening on enp1s0, link-type EN10MB (Ethernet), capture size 262144 bytes
16:42:37.321194 IP (tos 0x0, ttl 64, id 1567, offset 0, flags [DF], proto TCP (6), length 60)
192.168.122.185.34050 > 198.199.107.159.25: Flags [S], cksum 0x6df7 (incorrect -> 0xc5e2), seq 3824536030, win 64240, options [mss 1460,sackOK,TS val 17622374 ecr 0,nop,wscale 8], length 0
确认这实际上是主机的默认路由,即当源 IP 不是10.8.0.8
这样时,路由表t1
就会被触发:
# ip route
default via 192.168.122.1 dev enp1s0 proto dhcp metric 100
10.8.0.0/24 dev tun45 proto kernel scope link src 10.8.0.8
10.8.0.0/24 dev tun66 proto kernel scope link src 10.8.0.7
<...elided entries...>
# ip route get 198.199.107.159
198.199.107.159 via 192.168.122.1 dev enp1s0 src 192.168.122.185 uid 0
cache
master.cf
配置:
10.8.0.8:smtp inet n - y - - smtpd -v
-o smtpd_tls_key_file=/etc/letsencrypt/live/<domain>/privkey.pem
-o smtpd_tls_cert_file=/etc/letsencrypt/live/<domain>/fullchain.pem
-o smtp_bind_address=10.8.0.8
-o myhostname=<host.domain>
10.8.0.8:submission inet n - y - - smtpd -v
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_path=private/auth
-o smtpd_reject_unlisted_recipient=no
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o milter_macro_daemon_name=ORIGINATING
-o smtpd_tls_key_file=/etc/letsencrypt/live/<domain>/privkey.pem
-o smtpd_tls_cert_file=/etc/letsencrypt/live/<domain>/fullchain.pem
-o smtp_bind_address=10.8.0.8
-o myhostname=<host.domain>
10.8.0.8:smtps inet n - y - - smtpd -v
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_path=private/auth
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o milter_macro_daemon_name=ORIGINATING
-o smtpd_tls_key_file=/etc/letsencrypt/live/<domain>/privkey.pem
-o smtpd_tls_cert_file=/etc/letsencrypt/live/<domain>/fullchain.pem
-o smtp_bind_address=10.8.0.8
-o myhostname=<host.domain>
并postconf -n
输出:
# postconf -n
alias_database = hash:/etc/aliases
alias_maps = hash:/etc/aliases
append_dot_mydomain = no
biff = no
compatibility_level = 2
debug_peer_list = 81.3.6.165, 45.55.104.203, 34.209.113.130
delay_warning_time = 4h
disable_vrfy_command = yes
inet_interfaces = all
inet_protocols = all
invalid_hostname_reject_code = 550
mailbox_size_limit = 0
maximal_backoff_time = 3h
milter_default_action = accept
milter_protocol = 6
minimal_backoff_time = 180s
mydestination = localhost
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
myorigin = /etc/mailname
non_fqdn_reject_code = 550
non_smtpd_milters = $smtpd_milters
policyd-spf_time_limit = 3600s
readme_directory = no
recipient_delimiter = +
relayhost =
smtp_always_send_ehlo = yes
smtp_helo_timeout = 15s
smtp_rcpt_timeout = 15s
smtp_tls_security_level = may
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
smtpd_delay_reject = yes
smtpd_helo_required = yes
smtpd_helo_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname
smtpd_milters = local:opendkim/opendkim.sock
smtpd_recipient_limit = 40
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unlisted_recipient, reject_unauth_destination, check_policy_service unix:private/policyd-spf
smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, defer_unauth_destination
smtpd_sasl_auth_enable = yes
smtpd_sasl_path = private/auth
smtpd_sasl_security_options = noanonymous, noplaintext
smtpd_sasl_tls_security_options = noanonymous
smtpd_sasl_type = dovecot
smtpd_sender_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_sender, reject_unknown_sender_domain, reject_unknown_reverse_client_hostname
smtpd_timeout = 30s
smtpd_tls_auth_only = yes
smtpd_tls_security_level = may
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_use_tls = yes
strict_rfc821_envelopes = yes
unknown_address_reject_code = 550
unknown_client_reject_code = 550
unknown_hostname_reject_code = 550
unverified_recipient_reject_code = 550
unverified_sender_reject_code = 550
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf, mysql:/etc/postfix/mysql-virtual-email2email.cf
virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
virtual_transport = lmtp:unix:private/dovecot-lmtp
我没有在此主机上执行任何 SNAT、伪装或其他 iptables 操作。(这些操作都发生在 VPN 隧道的另一端。)
enp1s0
我在这里遗漏了什么?为什么出站后缀流量是通过而不是发出的tun45
?为什么它没有在 中设置的源 IP smtp_bind_address
?
答案1
这是配置问题master.cf
。上面显示的配置(在我的问题中)仅smtp_bind_address
针对入站流量进行设置,即针对监听守护进程。
对于出站流量,即当 postfix 守护进程向其他服务器发送邮件时,以下行master.cf
也必须指定绑定地址。在 default/sample 中,master.cf
该行如下所示:
smtp unix - - y - - smtp
它被许多其他参数掩盖,很容易被忽视。
将其更改为添加绑定地址,例如:
smtp unix - - y - - smtp
-o smtp_bind_address=10.8.0.9
由于我在同一台服务器上运行多个 postfix 守护程序,以便为具有单独公共 IP 和证书的多个域提供服务,因此我将我的守护程序更改为:
outbound_domain1.com unix - - y - - smtp
-o smtp_bind_address=10.8.0.8
-o smtp_helo_name=domain1.com
...然后添加一行/etc/postfix/sender_transport
以将此出站守护程序映射到它所服务的电子邮件域:
@domain1.com outbound_domain1.com
当然你还必须告诉 postfix 使用该传输图,如下所示main.cf
:
sender_dependent_default_transport_maps = hash:/etc/postfix/sender_transport
然后运行postmap
以生成 Postfix 用于这些查找的哈希文件。
答案2
请看一下这个问题:防止 Postfix 通过错误的网络接口发送电子邮件。
在那篇帖子中,人们说smtp_bind_address
如果配置的 inet_interface 不可用,将故障转移到另一个 inet_interface。在您的例子中,smtp_bind_address
指向绑定到 tun0 的静态 IP。当 tun0 启动时,它将通过 tun0 传递出去。如果 tun0 关闭,则客户端绑定将失败,导致 postfix 恢复到不绑定客户端 TCP 端点的默认行为,因此它将使用连接到 eth0 的默认路由。