-TPSC_DNSBL_HEAD
-TPSC_DNSBL_SCORE
-TPSC_DNSBL_SITE
+-TPSC_ENDPT_LOOKUP_INFO
+-TPSC_HAPROXY_STATE
-TPSC_SMTPD_COMMAND
-TPSC_STARTTLS
-TPSC_STATE
-TSMFICTX
-TSMTPD_CMD
-TSMTPD_DEFER
+-TSMTPD_ENDPT_LOOKUP_INFO
-TSMTPD_PROXY
-TSMTPD_RBL_EXPAND_CONTEXT
-TSMTPD_RBL_STATE
Bugfix (introduced: 20031216-21): with soft_bounce=yes, the
SMTP client did not move on to the next MX host or fallback
relay after a 5xx reply. File: smtp/smtp_trouble.c.
+
+20120527-8
+
+ Infrastructure: limited support to shrink VSTREAM buffers.
+ The change takes place when reading from (a stream for the
+ first time | an empty buffer) or when writing to (a stream
+ for the first time | a full buffer). TODO: the change should
+ also happen after purging or flushing a buffer. File:
+ util/vstream.c.
+
+20120531-617
+
+ Feature: haproxy support in postscreen(8) and smtpd(8). To
+ enable, specify "smtpd_upstream_proxy_protocol = haproxy"
+ or "postscreen_upstream_proxy_protocol = haproxy". Files:
+ mantools/postlink, proto/postconf.proto, global/Makefile.in,
+ global/haproxy_srvr.c, global/haproxy_srvr.h, global/mail_params.h,
+ global/mail_proto.h, master/single_server.c, master/multi_server.c,
+ master/event_server.c, postscreen/Makefile.in,
+ postscreen/postscreen.c, postscreen/postscreen.h,
+ postscreen/postscreen_endpt.c, postscreen/postscreen_haproxy.c,
+ postscreen/postscreen_haproxy.h, postscreen/postscreen_send.c,
+ postscreen/postscreen_state.c, smtpd/Makefile.in, smtpd/smtpd.h,
+ smtpd/smtpd_peer.c, smtpd/smtpd_sasl_glue.c, smtpd/smtpd_haproxy.c,
+ util/Makefile.in, util/listen.h, util/recv_pass_attr.c,
+ util/stream_listen.c, util/sys_defs.h, util/unix_pass_listen.c.
+
+
+20120618
+
+ Cleanup: made the postscreen-to-smtpd haproxy attribute
+ transmission more robust for Solaris. Files: util/sys_defs.h,
+ util/connect.h, util/steam_listen.c, postscreen/postscreen_send.c.
+
+ Cleanup: simplified the "stream used" workaround. Files:
+ util/vstream.h, master/event_server.c, master/multi_server.c.
+
+20120621
+
+ Cleanup: simplified workarounds for Solaris streams versus
+ UNIX-domain sockets. Files: util/pass_accept.c (new),
+ util/pass_trigger.c (new), util/stream_pass_connect.c
+ (deleted), util/unix_pass_listen.c (deleted),
+ util/unix_pass_trigger.c (deleted), updated header files,
+ and replaced PASS_XXX macros by pass_xxx function calls.
+
+ Cleanup: don't clobber errno when logging a problem.
+ File util/msg_output.c.
If you upgrade from Postfix 2.8 or earlier, read RELEASE_NOTES-2.9
before proceeding.
+Incompatible changes with snapshot 20120625
+===========================================
+
+The postscreen(8)-to-smtpd(8) protocol has changed. To avoid "cannot
+receive connection attributes" warnings and dropped connections,
+execute the command "postfix reload". No mail will be lost as long
+as the remote SMTP client tries again later.
+
+Major changes with snapshot 20120625
+====================================
+
+Support for upstream proxy agent in the postscreen(8) and smtpd(8)
+daemons. To enable the haproxy protocol, specify one of the
+following:
+
+ postscreen_upstream_proxy_protocol = haproxy
+ smtpd_upstream_proxy_protocol = haproxy
+
+Note 1: smtpd_upstream_proxy_protocol can't be used behind postscreen.
+
+Note 2: To use the nginx proxy with smtpd(8), enable the XCLIENT
+protocol with smtpd_authorized_xclient_hosts. This supports SASL
+authentication in the proxy agent (Postfix 2.9 and later).
+
Major changes with snapshot 20120422
====================================
<p> This feature is available in Postfix 2.8 and later. </p>
+</DD>
+
+<DT><b><a name="postscreen_upstream_proxy_protocol">postscreen_upstream_proxy_protocol</a>
+(default: empty)</b></DT><DD>
+
+<p> The name of the proxy protocol used by an optional before-postscreen
+proxy agent. When a proxy agent is used, this protocol conveys local
+and remote address and port information. Specify
+"<a href="postconf.5.html#postscreen_upstream_proxy_protocol">postscreen_upstream_proxy_protocol</a> = haproxy" to enable the haproxy
+protocol. <p>
+
+<p> This feature is available in Postfix 2.10 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="postscreen_upstream_proxy_timeout">postscreen_upstream_proxy_timeout</a>
+(default: 5s)</b></DT><DD>
+
+<p> The time limit for the proxy protocol specified with the
+<a href="postconf.5.html#postscreen_upstream_proxy_protocol">postscreen_upstream_proxy_protocol</a> parameter. </p>
+
+<p> This feature is available in Postfix 2.10 and later. </p>
+
+
</DD>
<DT><b><a name="postscreen_use_tls">postscreen_use_tls</a>
<p> This feature is available in Postfix 2.2 and later. </p>
+</DD>
+
+<DT><b><a name="smtpd_upstream_proxy_protocol">smtpd_upstream_proxy_protocol</a>
+(default: empty)</b></DT><DD>
+
+<p> The name of the proxy protocol used by an optional before-smtpd
+proxy agent. When a proxy agent is used, this protocol conveys local
+and remote address and port information. Specify
+"<a href="postconf.5.html#smtpd_upstream_proxy_protocol">smtpd_upstream_proxy_protocol</a> = haproxy" to enable the haproxy
+protocol. </p>
+
+<p> NOTE: To use the nginx proxy with <a href="smtpd.8.html">smtpd(8)</a>, enable the XCLIENT
+protocol with <a href="postconf.5.html#smtpd_authorized_xclient_hosts">smtpd_authorized_xclient_hosts</a>. This supports SASL
+authentication in the proxy agent (Postfix 2.9 and later). <p>
+
+<p> This feature is available in Postfix 2.10 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="smtpd_upstream_proxy_timeout">smtpd_upstream_proxy_timeout</a>
+(default: 5s)</b></DT><DD>
+
+<p> The time limit for the proxy protocol specified with the
+<a href="postconf.5.html#smtpd_upstream_proxy_protocol">smtpd_upstream_proxy_protocol</a> parameter. </p>
+
+<p> This feature is available in Postfix 2.10 and later. </p>
+
+
</DD>
<DT><b><a name="smtpd_use_tls">smtpd_use_tls</a>
Safety net to keep mail queued that would otherwise
be returned to the sender.
+<b>BEFORE-POSTSCREEN PROXY AGENT</b>
+ Available in Postfix version 2.10 and later:
+
+ <b><a href="postconf.5.html#postscreen_upstream_proxy_protocol">postscreen_upstream_proxy_protocol</a> (empty)</b>
+ The name of the proxy protocol used by an optional
+ before-postscreen proxy agent.
+
+ <b><a href="postconf.5.html#postscreen_upstream_proxy_timeout">postscreen_upstream_proxy_timeout</a> (5s)</b>
+ The time limit for the proxy protocol specified
+ with the <a href="postconf.5.html#postscreen_upstream_proxy_protocol">postscreen_upstream_proxy_protocol</a> parame-
+ ter.
+
<b>PERMANENT WHITE/BLACKLIST TEST</b>
- This test is executed immediately after a remote SMTP
- client connects. If a client is permanently whitelisted,
- the client will be handed off immediately to a Postfix
+ This test is executed immediately after a remote SMTP
+ client connects. If a client is permanently whitelisted,
+ the client will be handed off immediately to a Postfix
SMTP server process.
<b><a href="postconf.5.html#postscreen_access_list">postscreen_access_list</a> (<a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>)</b>
addresses.
<b><a href="postconf.5.html#postscreen_blacklist_action">postscreen_blacklist_action</a> (ignore)</b>
- The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
- SMTP client is permanently blacklisted with the
+ The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
+ SMTP client is permanently blacklisted with the
<a href="postconf.5.html#postscreen_access_list">postscreen_access_list</a> parameter.
<b>MAIL EXCHANGER POLICY TESTS</b>
- When <a href="postscreen.8.html"><b>postscreen</b>(8)</a> is configured to monitor all primary
- and backup MX addresses, it can refuse to whitelist
- clients that connect to a backup MX address only. For
- small sites, this requires configuring primary and backup
- MX addresses on the same MTA. Larger sites would have to
- share the <a href="postscreen.8.html"><b>postscreen</b>(8)</a> cache between primary and backup
+ When <a href="postscreen.8.html"><b>postscreen</b>(8)</a> is configured to monitor all primary
+ and backup MX addresses, it can refuse to whitelist
+ clients that connect to a backup MX address only. For
+ small sites, this requires configuring primary and backup
+ MX addresses on the same MTA. Larger sites would have to
+ share the <a href="postscreen.8.html"><b>postscreen</b>(8)</a> cache between primary and backup
MTAs, which would introduce a common point of failure.
<b><a href="postconf.5.html#postscreen_whitelist_interfaces">postscreen_whitelist_interfaces</a> (<a href="DATABASE_README.html#types">static</a>:all)</b>
- A list of local <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server IP addresses
- where a non-whitelisted remote SMTP client can
- obtain <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s temporary whitelist status.
+ A list of local <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server IP addresses
+ where a non-whitelisted remote SMTP client can
+ obtain <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s temporary whitelist status.
<b>BEFORE-GREETING TESTS</b>
- These tests are executed before the remote SMTP client
+ These tests are executed before the remote SMTP client
receives the "220 servername" greeting. If no tests remain
- after the successful completion of this phase, the client
- will be handed off immediately to a Postfix SMTP server
+ after the successful completion of this phase, the client
+ will be handed off immediately to a Postfix SMTP server
process.
<b><a href="postconf.5.html#dnsblog_service_name">dnsblog_service_name</a> (dnsblog)</b>
- The name of the <a href="dnsblog.8.html"><b>dnsblog</b>(8)</a> service entry in mas-
+ The name of the <a href="dnsblog.8.html"><b>dnsblog</b>(8)</a> service entry in mas-
ter.cf.
<b><a href="postconf.5.html#postscreen_dnsbl_action">postscreen_dnsbl_action</a> (ignore)</b>
- The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
- SMTP client's combined DNSBL score is equal to or
- greater than a threshold (as defined with the
+ The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
+ SMTP client's combined DNSBL score is equal to or
+ greater than a threshold (as defined with the
<a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> and <a href="postconf.5.html#postscreen_dnsbl_threshold">postscreen_dnsbl_thresh</a>-
<a href="postconf.5.html#postscreen_dnsbl_threshold">old</a> parameters).
<b><a href="postconf.5.html#postscreen_dnsbl_reply_map">postscreen_dnsbl_reply_map</a> (empty)</b>
- A mapping from actual DNSBL domain name which
- includes a secret password, to the DNSBL domain
+ A mapping from actual DNSBL domain name which
+ includes a secret password, to the DNSBL domain
name that postscreen will reply with when it
rejects mail.
<b><a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> (empty)</b>
- Optional list of DNS white/blacklist domains, fil-
+ Optional list of DNS white/blacklist domains, fil-
ters and weight factors.
<b><a href="postconf.5.html#postscreen_dnsbl_threshold">postscreen_dnsbl_threshold</a> (1)</b>
- The inclusive lower bound for blocking a remote
- SMTP client, based on its combined DNSBL score as
- defined with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter.
+ The inclusive lower bound for blocking a remote
+ SMTP client, based on its combined DNSBL score as
+ defined with the <a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> parameter.
<b><a href="postconf.5.html#postscreen_greet_action">postscreen_greet_action</a> (ignore)</b>
- The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
- SMTP client speaks before its turn within the time
+ The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
+ SMTP client speaks before its turn within the time
specified with the <a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> parameter.
<b><a href="postconf.5.html#postscreen_greet_banner">postscreen_greet_banner</a> ($<a href="postconf.5.html#smtpd_banner">smtpd_banner</a>)</b>
The <i>text</i> in the optional "220-<i>text</i>..." server
response that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> sends ahead of the real
Postfix SMTP server's "220 text..." response, in an
- attempt to confuse bad SMTP clients so that they
+ attempt to confuse bad SMTP clients so that they
speak before their turn (pre-greet).
<b><a href="postconf.5.html#postscreen_greet_wait">postscreen_greet_wait</a> (${stress?2}${stress:6}s)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will wait for
- an SMTP client to send a command before its turn,
- and for DNS blocklist lookup results to arrive
- (default: up to 2 seconds under stress, up to 6
+ an SMTP client to send a command before its turn,
+ and for DNS blocklist lookup results to arrive
+ (default: up to 2 seconds under stress, up to 6
seconds otherwise).
<b><a href="postconf.5.html#smtpd_service_name">smtpd_service_name</a> (smtpd)</b>
- The internal service that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> hands off
+ The internal service that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> hands off
allowed connections to.
<b>AFTER-GREETING TESTS</b>
- These tests are executed after the remote SMTP client
+ These tests are executed after the remote SMTP client
receives the "220 servername" greeting. If a client passes
- all tests during this phase, it will receive a 4XX
- response to RCPT TO commands until the client hangs up.
+ all tests during this phase, it will receive a 4XX
+ response to RCPT TO commands until the client hangs up.
After this, the client will be allowed to talk directly to
a Postfix SMTP server process.
<b><a href="postconf.5.html#postscreen_bare_newline_action">postscreen_bare_newline_action</a> (ignore)</b>
- The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
- SMTP client sends a bare newline character, that
+ The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
+ SMTP client sends a bare newline character, that
is, a newline not preceded by carriage return.
<b><a href="postconf.5.html#postscreen_bare_newline_enable">postscreen_bare_newline_enable</a> (no)</b>
- Enable "bare newline" SMTP protocol tests in the
+ Enable "bare newline" SMTP protocol tests in the
<a href="postscreen.8.html"><b>postscreen</b>(8)</a> server.
<b><a href="postconf.5.html#postscreen_disable_vrfy_command">postscreen_disable_vrfy_command</a> ($<a href="postconf.5.html#disable_vrfy_command">disable_vrfy_command</a>)</b>
- Disable the SMTP VRFY command in the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
+ Disable the SMTP VRFY command in the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
daemon.
<b><a href="postconf.5.html#postscreen_forbidden_commands">postscreen_forbidden_commands</a> ($<a href="postconf.5.html#smtpd_forbidden_commands">smtpd_forbidden_commands</a>)</b>
siders in violation of the SMTP protocol.
<b><a href="postconf.5.html#postscreen_helo_required">postscreen_helo_required</a> ($<a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a>)</b>
- Require that a remote SMTP client sends HELO or
+ Require that a remote SMTP client sends HELO or
EHLO before commencing a MAIL transaction.
<b><a href="postconf.5.html#postscreen_non_smtp_command_action">postscreen_non_smtp_command_action</a> (drop)</b>
- The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
- SMTP client sends non-SMTP commands as specified
+ The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
+ SMTP client sends non-SMTP commands as specified
with the <a href="postconf.5.html#postscreen_forbidden_commands">postscreen_forbidden_commands</a> parameter.
<b><a href="postconf.5.html#postscreen_non_smtp_command_enable">postscreen_non_smtp_command_enable</a> (no)</b>
- Enable "non-SMTP command" tests in the
+ Enable "non-SMTP command" tests in the
<a href="postscreen.8.html"><b>postscreen</b>(8)</a> server.
<b><a href="postconf.5.html#postscreen_pipelining_action">postscreen_pipelining_action</a> (enforce)</b>
- The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
- SMTP client sends multiple commands instead of
- sending one command and waiting for the server to
+ The action that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> takes when a remote
+ SMTP client sends multiple commands instead of
+ sending one command and waiting for the server to
respond.
<b><a href="postconf.5.html#postscreen_pipelining_enable">postscreen_pipelining_enable</a> (no)</b>
- Enable "pipelining" SMTP protocol tests in the
+ Enable "pipelining" SMTP protocol tests in the
<a href="postscreen.8.html"><b>postscreen</b>(8)</a> server.
<b>CACHE CONTROLS</b>
<b><a href="postconf.5.html#postscreen_cache_cleanup_interval">postscreen_cache_cleanup_interval</a> (12h)</b>
- The amount of time between <a href="postscreen.8.html"><b>postscreen</b>(8)</a> cache
+ The amount of time between <a href="postscreen.8.html"><b>postscreen</b>(8)</a> cache
cleanup runs.
<b><a href="postconf.5.html#postscreen_cache_map">postscreen_cache_map</a> (btree:$data_direc-</b>
<b>tory/postscreen_cache)</b>
- Persistent storage for the <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server
+ Persistent storage for the <a href="postscreen.8.html"><b>postscreen</b>(8)</a> server
decisions.
<b><a href="postconf.5.html#postscreen_cache_retention_time">postscreen_cache_retention_time</a> (7d)</b>
The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will cache an
- expired temporary whitelist entry before it is
+ expired temporary whitelist entry before it is
removed.
<b><a href="postconf.5.html#postscreen_bare_newline_ttl">postscreen_bare_newline_ttl</a> (30d)</b>
- The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
+ The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
result from a successful "bare newline" SMTP proto-
col test.
<b><a href="postconf.5.html#postscreen_dnsbl_ttl">postscreen_dnsbl_ttl</a> (1h)</b>
- The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
+ The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
result from a successful DNS blocklist test.
<b><a href="postconf.5.html#postscreen_greet_ttl">postscreen_greet_ttl</a> (1d)</b>
- The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
+ The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
result from a successful PREGREET test.
<b><a href="postconf.5.html#postscreen_non_smtp_command_ttl">postscreen_non_smtp_command_ttl</a> (30d)</b>
- The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
- result from a successful "non_smtp_command" SMTP
+ The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
+ result from a successful "non_smtp_command" SMTP
protocol test.
<b><a href="postconf.5.html#postscreen_pipelining_ttl">postscreen_pipelining_ttl</a> (30d)</b>
- The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
+ The amount of time that <a href="postscreen.8.html"><b>postscreen</b>(8)</a> will use the
result from a successful "pipelining" SMTP protocol
test.
<b>RESOURCE CONTROLS</b>
<b><a href="postconf.5.html#line_length_limit">line_length_limit</a> (2048)</b>
- Upon input, long lines are chopped up into pieces
- of at most this length; upon delivery, long lines
+ Upon input, long lines are chopped up into pieces
+ of at most this length; upon delivery, long lines
are reconstructed.
<b><a href="postconf.5.html#postscreen_client_connection_count_limit">postscreen_client_connection_count_limit</a></b>
<b>($<a href="postconf.5.html#smtpd_client_connection_count_limit">smtpd_client_connection_count_limit</a>)</b>
- How many simultaneous connections any remote SMTP
- client is allowed to have with the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
+ How many simultaneous connections any remote SMTP
+ client is allowed to have with the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
daemon.
<b><a href="postconf.5.html#postscreen_command_count_limit">postscreen_command_count_limit</a> (20)</b>
- The limit on the total number of commands per SMTP
- session for <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s built-in SMTP protocol
+ The limit on the total number of commands per SMTP
+ session for <a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s built-in SMTP protocol
engine.
<b><a href="postconf.5.html#postscreen_command_time_limit">postscreen_command_time_limit</a> (${stress?10}${stress:300}s)</b>
- The time limit to read an entire command line with
+ The time limit to read an entire command line with
<a href="postscreen.8.html"><b>postscreen</b>(8)</a>'s built-in SMTP protocol engine.
<b><a href="postconf.5.html#postscreen_post_queue_limit">postscreen_post_queue_limit</a> ($<a href="postconf.5.html#default_process_limit">default_process_limit</a>)</b>
- The number of clients that can be waiting for ser-
+ The number of clients that can be waiting for ser-
vice from a real Postfix SMTP server process.
<b><a href="postconf.5.html#postscreen_pre_queue_limit">postscreen_pre_queue_limit</a> ($<a href="postconf.5.html#default_process_limit">default_process_limit</a>)</b>
- The number of non-whitelisted clients that can be
- waiting for a decision whether they will receive
+ The number of non-whitelisted clients that can be
+ waiting for a decision whether they will receive
service from a real Postfix SMTP server process.
<b><a href="postconf.5.html#postscreen_watchdog_timeout">postscreen_watchdog_timeout</a> (10s)</b>
- How much time a <a href="postscreen.8.html"><b>postscreen</b>(8)</a> process may take to
- respond to a remote SMTP client command or to per-
+ How much time a <a href="postscreen.8.html"><b>postscreen</b>(8)</a> process may take to
+ respond to a remote SMTP client command or to per-
form a cache operation before it is terminated by a
built-in watchdog timer.
<b>STARTTLS CONTROLS</b>
<b><a href="postconf.5.html#postscreen_tls_security_level">postscreen_tls_security_level</a> ($<a href="postconf.5.html#smtpd_tls_security_level">smtpd_tls_security_level</a>)</b>
- The SMTP TLS security level for the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
- server; when a non-empty value is specified, this
+ The SMTP TLS security level for the <a href="postscreen.8.html"><b>postscreen</b>(8)</a>
+ server; when a non-empty value is specified, this
overrides the obsolete parameters
<a href="postconf.5.html#postscreen_use_tls">postscreen_use_tls</a> and <a href="postconf.5.html#postscreen_enforce_tls">postscreen_enforce_tls</a>.
<b><a href="postconf.5.html#tlsproxy_service_name">tlsproxy_service_name</a> (tlsproxy)</b>
- The name of the <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> service entry in mas-
+ The name of the <a href="tlsproxy.8.html"><b>tlsproxy</b>(8)</a> service entry in mas-
ter.cf.
<b>OBSOLETE STARTTLS SUPPORT CONTROLS</b>
- These parameters are supported for compatibility with
+ These parameters are supported for compatibility with
<a href="smtpd.8.html"><b>smtpd</b>(8)</a> legacy parameters.
<b><a href="postconf.5.html#postscreen_use_tls">postscreen_use_tls</a> ($<a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a>)</b>
- Opportunistic TLS: announce STARTTLS support to
+ Opportunistic TLS: announce STARTTLS support to
remote SMTP clients, but do not require that
clients use TLS encryption.
<b><a href="postconf.5.html#postscreen_enforce_tls">postscreen_enforce_tls</a> ($<a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a>)</b>
- Mandatory TLS: announce STARTTLS support to remote
- SMTP clients, and require that clients use TLS
+ Mandatory TLS: announce STARTTLS support to remote
+ SMTP clients, and require that clients use TLS
encryption.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
+ The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
- The maximal number of digits after the decimal
+ The maximal number of digits after the decimal
point when logging sub-second delay values.
<b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
- The location of all postfix administrative com-
+ The location of all postfix administrative com-
mands.
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
- The maximum amount of time that an idle Postfix
- daemon process waits for an incoming connection
+ The maximum amount of time that an idle Postfix
+ daemon process waits for an incoming connection
before terminating voluntarily.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
- The process ID of a Postfix command or daemon
+ The process ID of a Postfix command or daemon
process.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
- The process name of a Postfix command or daemon
+ The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
- The mail system name that is prepended to the
- process name in syslog records, so that "smtpd"
+ The mail system name that is prepended to the
+ process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
<b>SEE ALSO</b>
<a href="POSTSCREEN_README.html">POSTSCREEN_README</a>, Postfix Postscreen Howto
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>HISTORY</b>
This service was introduced with Postfix version 2.8.
- Many ideas in <a href="postscreen.8.html"><b>postscreen</b>(8)</a> were explored in earlier work
- by Michael Tokarev, in OpenBSD spamd, and in MailChannels
+ Many ideas in <a href="postscreen.8.html"><b>postscreen</b>(8)</a> were explored in earlier work
+ by Michael Tokarev, in OpenBSD spamd, and in MailChannels
Traffic Control.
<b>AUTHOR(S)</b>
addresses with the domain specified in the
<a href="postconf.5.html#remote_header_rewrite_domain">remote_header_rewrite_domain</a> parameter.
+<b>BEFORE-SMTPD PROXY AGENT</b>
+ Available in Postfix version 2.10 and later:
+
+ <b><a href="postconf.5.html#smtpd_upstream_proxy_protocol">smtpd_upstream_proxy_protocol</a> (empty)</b>
+ The name of the proxy protocol used by an optional
+ before-smtpd proxy agent.
+
+ <b><a href="postconf.5.html#smtpd_upstream_proxy_timeout">smtpd_upstream_proxy_timeout</a> (5s)</b>
+ The time limit for the proxy protocol specified
+ with the <a href="postconf.5.html#smtpd_upstream_proxy_protocol">smtpd_upstream_proxy_protocol</a> parameter.
+
<b>AFTER QUEUE EXTERNAL CONTENT INSPECTION CONTROLS</b>
As of version 1.0, Postfix can be configured to send new
mail to an external content filter AFTER the mail is
# Non-production: needs thorough testing, or major changes are still
# needed before the code stabilizes.
-#CCARGS="$CCARGS -DNONPROD"
+CCARGS="$CCARGS -DNONPROD"
sed 's/ / /g' <<EOF
SYSTYPE = $SYSTYPE
for details.
.PP
This feature is available in Postfix 2.8 and later.
+.SH postscreen_upstream_proxy_protocol (default: empty)
+The name of the proxy protocol used by an optional before-postscreen
+proxy agent. When a proxy agent is used, this protocol conveys local
+and remote address and port information. Specify
+"postscreen_upstream_proxy_protocol = haproxy" to enable the haproxy
+protocol.
+.PP
+This feature is available in Postfix 2.10 and later.
+.SH postscreen_upstream_proxy_timeout (default: 5s)
+The time limit for the proxy protocol specified with the
+postscreen_upstream_proxy_protocol parameter.
+.PP
+This feature is available in Postfix 2.10 and later.
.SH postscreen_use_tls (default: $smtpd_use_tls)
Opportunistic TLS: announce STARTTLS support to remote SMTP clients,
but do not require that clients use TLS encryption.
purpose.
.PP
This feature is available in Postfix 2.2 and later.
+.SH smtpd_upstream_proxy_protocol (default: empty)
+The name of the proxy protocol used by an optional before-smtpd
+proxy agent. When a proxy agent is used, this protocol conveys local
+and remote address and port information. Specify
+"smtpd_upstream_proxy_protocol = haproxy" to enable the haproxy
+protocol.
+.PP
+NOTE: To use the nginx proxy with \fBsmtpd\fR(8), enable the XCLIENT
+protocol with smtpd_authorized_xclient_hosts. This supports SASL
+authentication in the proxy agent (Postfix 2.9 and later).
+.PP
+This feature is available in Postfix 2.10 and later.
+.SH smtpd_upstream_proxy_timeout (default: 5s)
+The time limit for the proxy protocol specified with the
+smtpd_upstream_proxy_protocol parameter.
+.PP
+This feature is available in Postfix 2.10 and later.
.SH smtpd_use_tls (default: no)
Opportunistic TLS: announce STARTTLS support to remote SMTP clients,
but do not require that clients use TLS encryption.
.IP "\fBsoft_bounce (no)\fR"
Safety net to keep mail queued that would otherwise be returned to
the sender.
+.SH "BEFORE-POSTSCREEN PROXY AGENT"
+.na
+.nf
+.ad
+.fi
+Available in Postfix version 2.10 and later:
+.IP "\fBpostscreen_upstream_proxy_protocol (empty)\fR"
+The name of the proxy protocol used by an optional before-postscreen
+proxy agent.
+.IP "\fBpostscreen_upstream_proxy_timeout (5s)\fR"
+The time limit for the proxy protocol specified with the
+postscreen_upstream_proxy_protocol parameter.
.SH "PERMANENT WHITE/BLACKLIST TEST"
.na
.nf
at all, or rewrite message headers and update incomplete addresses
with the domain specified in the remote_header_rewrite_domain
parameter.
+.SH "BEFORE-SMTPD PROXY AGENT"
+.na
+.nf
+.ad
+.fi
+Available in Postfix version 2.10 and later:
+.IP "\fBsmtpd_upstream_proxy_protocol (empty)\fR"
+The name of the proxy protocol used by an optional before-smtpd
+proxy agent.
+.IP "\fBsmtpd_upstream_proxy_timeout (5s)\fR"
+The time limit for the proxy protocol specified with the
+smtpd_upstream_proxy_protocol parameter.
.SH "AFTER QUEUE EXTERNAL CONTENT INSPECTION CONTROLS"
.na
.nf
s;\bsmtpd_use_tls\b;<a href="postconf.5.html#smtpd_use_tls">$&</a>;g;
s;\bsmtpd_reject_footer\b;<a href="postconf.5.html#smtpd_reject_footer">$&</a>;g;
s;\bsmtpd_per_record_deadline\b;<a href="postconf.5.html#smtpd_per_record_deadline">$&</a>;g;
+ s;\bsmtpd_upstream_proxy_protocol\b;<a href="postconf.5.html#smtpd_upstream_proxy_protocol">$&</a>;g;
+ s;\bsmtpd_upstream_proxy_timeout\b;<a href="postconf.5.html#smtpd_upstream_proxy_timeout">$&</a>;g;
s;\btls_daemon_random_bytes\b;<a href="postconf.5.html#tls_daemon_random_bytes">$&</a>;g;
s;\btls_daemon_random_source\b;<a href="postconf.5.html#tls_daemon_random_source">$&</a>;g;
s;\btls_ran[-</Bb>]*\n* *[<Bb>]*dom_bytes\b;<a href="postconf.5.html#tls_random_bytes">$&</a>;g;
s;\bpostscreen_reject_footer\b;<a href="postconf.5.html#postscreen_reject_footer">$&</a>;g;
s;\bpostscreen_command_filter\b;<a href="postconf.5.html#postscreen_command_filter">$&</a>;g;
s;\bpostscreen_whitelist_interfaces\b;<a href="postconf.5.html#postscreen_whitelist_interfaces">$&</a>;g;
+ s;\bpostscreen_upstream_proxy_protocol\b;<a href="postconf.5.html#postscreen_upstream_proxy_protocol">$&</a>;g;
+ s;\bpostscreen_upstream_proxy_timeout\b;<a href="postconf.5.html#postscreen_upstream_proxy_timeout">$&</a>;g;
s;\btlsproxy_watchdog_timeout\b;<a href="postconf.5.html#tlsproxy_watchdog_timeout">$&</a>;g;
s;\btlsproxy_enforce_tls\b;<a href="postconf.5.html#tlsproxy_enforce_tls">$&</a>;g;
<p> This feature is available in Postfix 2.9 and later. </p>
+%PARAM postscreen_upstream_proxy_protocol
+
+<p> The name of the proxy protocol used by an optional before-postscreen
+proxy agent. When a proxy agent is used, this protocol conveys local
+and remote address and port information. Specify
+"postscreen_upstream_proxy_protocol = haproxy" to enable the haproxy
+protocol. <p>
+
+<p> This feature is available in Postfix 2.10 and later. </p>
+
+%PARAM postscreen_upstream_proxy_timeout 5s
+
+<p> The time limit for the proxy protocol specified with the
+postscreen_upstream_proxy_protocol parameter. </p>
+
+<p> This feature is available in Postfix 2.10 and later. </p>
+
+%PARAM smtpd_upstream_proxy_protocol
+
+<p> The name of the proxy protocol used by an optional before-smtpd
+proxy agent. When a proxy agent is used, this protocol conveys local
+and remote address and port information. Specify
+"smtpd_upstream_proxy_protocol = haproxy" to enable the haproxy
+protocol. </p>
+
+<p> NOTE: To use the nginx proxy with smtpd(8), enable the XCLIENT
+protocol with smtpd_authorized_xclient_hosts. This supports SASL
+authentication in the proxy agent (Postfix 2.9 and later). <p>
+
+<p> This feature is available in Postfix 2.10 and later. </p>
+
+%PARAM smtpd_upstream_proxy_timeout 5s
+
+<p> The time limit for the proxy protocol specified with the
+smtpd_upstream_proxy_protocol parameter. </p>
+
+<p> This feature is available in Postfix 2.10 and later. </p>
+
%PARAM enable_long_queue_ids no
<p> Enable long, non-repeating, queue IDs (queue file names). The
match_service.c mail_conf_nint.c addr_match_list.c mail_conf_nbool.c \
smtp_reply_footer.c safe_ultostr.c verify_sender_addr.c \
dict_memcache.c mail_version.c memcache_proto.c server_acl.c \
- mkmap_fail.c
+ mkmap_fail.c haproxy_srvr.c
OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \
clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \
match_service.o mail_conf_nint.o addr_match_list.o mail_conf_nbool.o \
smtp_reply_footer.o safe_ultostr.o verify_sender_addr.o \
dict_memcache.o mail_version.o memcache_proto.o server_acl.o \
- mkmap_fail.o
+ mkmap_fail.o haproxy_srvr.o
HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \
conv_time.h db_common.h debug_peer.h debug_process.h defer.h \
verp_sender.h wildcard_inet_addr.h xtext.h delivered_hdr.h \
fold_addr.h header_body_checks.h data_redirect.h match_service.h \
addr_match_list.h smtp_reply_footer.h safe_ultostr.h \
- verify_sender_addr.h dict_memcache.h memcache_proto.h server_acl.h
+ verify_sender_addr.h dict_memcache.h memcache_proto.h server_acl.h \
+ haproxy_srvr.h
TESTSRC = rec2stream.c stream2rec.c recdump.c
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
fold_addr.o: ../../include/vstring.h
fold_addr.o: fold_addr.c
fold_addr.o: fold_addr.h
+haproxy_srvr.o: ../../include/msg.h
+haproxy_srvr.o: ../../include/myaddrinfo.h
+haproxy_srvr.o: ../../include/stringops.h
+haproxy_srvr.o: ../../include/sys_defs.h
+haproxy_srvr.o: ../../include/valid_hostname.h
+haproxy_srvr.o: ../../include/vbuf.h
+haproxy_srvr.o: ../../include/vstring.h
+haproxy_srvr.o: haproxy_srvr.c
+haproxy_srvr.o: haproxy_srvr.h
header_body_checks.o: ../../include/argv.h
header_body_checks.o: ../../include/dict.h
header_body_checks.o: ../../include/msg.h
--- /dev/null
+/*++
+/* NAME
+/* haproxy_srvr 3
+/* SUMMARY
+/* server-side haproxy protocol support
+/* SYNOPSIS
+/* #include <haproxy_srvr.h>
+/*
+/* const char *haproxy_srvr_parse(str,
+/* smtp_client_addr, smtp_client_port,
+/* smtp_server_addr, smtp_server_port)
+/* const char *str;
+/* MAI_HOSTADDR_STR *smtp_client_addr,
+/* MAI_SERVPORT_STR *smtp_client_port,
+/* MAI_HOSTADDR_STR *smtp_server_addr,
+/* MAI_SERVPORT_STR *smtp_server_port;
+/* DESCRIPTION
+/* haproxy_srvr_parse() parses a haproxy line. The result is
+/* null in case of success, a pointer to text (with the error
+/* type) in case of error. If both IPv6 and IPv4 support are
+/* enabled, IPV4_IN_IPV6 address syntax (::ffff:1.2.3.4) is
+/* converted to IPV4 syntax.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <myaddrinfo.h>
+#include <valid_hostname.h>
+#include <stringops.h>
+#include <mymalloc.h>
+#include <inet_proto.h>
+
+/* Global library. */
+
+#include <haproxy_srvr.h>
+
+/* Application-specific. */
+
+static INET_PROTO_INFO *proto_info;
+
+/* haproxy_srvr_parse_lit - extract and validate string literal */
+
+static int haproxy_srvr_parse_lit(const char *str,...)
+{
+ va_list ap;
+ const char *cp;
+ int result = -1;
+
+ if (msg_verbose)
+ msg_info("haproxy_srvr_parse: %s", str);
+
+ if (str != 0) {
+ va_start(ap, str);
+ while (result < 0 && (cp = va_arg(ap, const char *)) != 0)
+ if (strcmp(str, cp) == 0)
+ result = 0;
+ va_end(ap);
+ }
+ return (result);
+}
+
+/* haproxy_srvr_parse_proto - parse and validate the protocol type */
+
+static int haproxy_srvr_parse_proto(const char *str, int *addr_family)
+{
+ if (msg_verbose)
+ msg_info("haproxy_srvr_parse: proto=%s", str);
+
+#ifdef AF_INET6
+ if (strcasecmp(str, "TCP6") == 0) {
+ if (strchr((char *) proto_info->sa_family_list, AF_INET6) != 0) {
+ *addr_family = AF_INET6;
+ return (0);
+ }
+ } else
+#endif
+ if (strcasecmp(str, "TCP4") == 0) {
+ if (strchr((char *) proto_info->sa_family_list, AF_INET) != 0) {
+ *addr_family = AF_INET;
+ return (0);
+ }
+ }
+ return (-1);
+}
+
+/* haproxy_srvr_parse_addr - extract and validate IP address */
+
+static int haproxy_srvr_parse_addr(const char *str, MAI_HOSTADDR_STR *addr,
+ int addr_family)
+{
+ if (msg_verbose)
+ msg_info("haproxy_srvr_parse: addr=%s proto=%d", str, addr_family);
+
+ if (str == 0 || strlen(str) >= sizeof(MAI_HOSTADDR_STR))
+ return (-1);
+
+ switch (addr_family) {
+#ifdef AF_INET6
+ case AF_INET6:
+ if (!valid_ipv6_hostaddr(str, DONT_GRIPE))
+ return (-1);
+ if (strncasecmp("::ffff:", str, 7) == 0
+ && strchr((char *) proto_info->sa_family_list, AF_INET) != 0) {
+ memcpy(addr->buf, str + 7, strlen(str) + 1 - 7);
+ return (0);
+ } else {
+ memcpy(addr->buf, str, strlen(str) + 1);
+ return (0);
+ }
+#endif
+ case AF_INET:
+ if (!valid_ipv4_hostaddr(str, DONT_GRIPE))
+ return (-1);
+ memcpy(addr->buf, str, strlen(str) + 1);
+ return (0);
+ default:
+ msg_panic("haproxy_srvr_parse: unexpected address family: %d",
+ addr_family);
+ }
+}
+
+/* haproxy_srvr_parse_port - extract and validate TCP port */
+
+static int haproxy_srvr_parse_port(const char *str, MAI_SERVPORT_STR *port)
+{
+ if (msg_verbose)
+ msg_info("haproxy_srvr_parse: port=%s", str);
+ if (str == 0 || strlen(str) >= sizeof(MAI_SERVPORT_STR)
+ || !valid_hostport(str, DONT_GRIPE)) {
+ return (-1);
+ } else {
+ memcpy(port->buf, str, strlen(str) + 1);
+ return (0);
+ }
+}
+
+/* haproxy_srvr_parse - parse haproxy line */
+
+const char *haproxy_srvr_parse(const char *str,
+ MAI_HOSTADDR_STR *smtp_client_addr,
+ MAI_SERVPORT_STR *smtp_client_port,
+ MAI_HOSTADDR_STR *smtp_server_addr,
+ MAI_SERVPORT_STR *smtp_server_port)
+{
+ char *saved_str = mystrdup(str);
+ char *cp = saved_str;
+ const char *err;
+ int addr_family;
+
+ if (proto_info == 0)
+ proto_info = inet_proto_info();
+
+ /*
+ * XXX We don't accept connections with the "UNKNOWN" protocol type,
+ * because those would sidestep address-based access control mechanisms.
+ */
+#define NEXT_TOKEN mystrtok(&cp, " \r\n")
+ if (haproxy_srvr_parse_lit(NEXT_TOKEN, "PROXY", (char *) 0) < 0)
+ err = "unexpected protocol header";
+ else if (haproxy_srvr_parse_proto(NEXT_TOKEN, &addr_family) < 0)
+ err = "unsupported protocol type";
+ else if (haproxy_srvr_parse_addr(NEXT_TOKEN, smtp_client_addr,
+ addr_family) < 0)
+ err = "unexpected client address syntax";
+ else if (haproxy_srvr_parse_addr(NEXT_TOKEN, smtp_server_addr,
+ addr_family) < 0)
+ err = "unexpected server address syntax";
+ else if (haproxy_srvr_parse_port(NEXT_TOKEN, smtp_client_port) < 0)
+ err = "unexpected client port syntax";
+ else if (haproxy_srvr_parse_port(NEXT_TOKEN, smtp_server_port) < 0)
+ err = "unexpected server port syntax";
+ else
+ err = 0;
+ myfree(saved_str);
+ return (err);
+}
--- /dev/null
+#ifndef _HAPROXY_SRVR_H_INCLUDED_
+#define _HAPROXY_SRVR_H_INCLUDED_
+
+/*++
+/* NAME
+/* haproxy_srvr 3h
+/* SUMMARY
+/* server-side haproxy protocol support
+/* SYNOPSIS
+/* #include <haproxy_srvr.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include <myaddrinfo.h>
+
+ /*
+ * External interface.
+ */
+extern const char *haproxy_srvr_parse(const char *,
+ MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *,
+ MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *);
+
+#define HAPROXY_PROTO_NAME "haproxy"
+#define HAPROXY_MAX_LEN (256 + 2)
+
+#ifndef DO_GRIPE
+#define DO_GRIPE 1
+#define DONT_GRIPE 0
+#endif
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
#define DEF_PSC_WLIST_IF "static:all"
extern char *var_psc_wlist_if;
+#define VAR_PSC_UPROXY_PROTO "postscreen_upstream_proxy_protocol"
+#define DEF_PSC_UPROXY_PROTO ""
+extern char *var_psc_uproxy_proto;
+
+#define VAR_PSC_UPROXY_TMOUT "postscreen_upstream_proxy_timeout"
+#define DEF_PSC_UPROXY_TMOUT "5s"
+extern int var_psc_uproxy_tmout;
+
#define VAR_DNSBLOG_SERVICE "dnsblog_service_name"
#define DEF_DNSBLOG_SERVICE MAIL_SERVICE_DNSBLOG
extern char *var_dnsblog_service;
#define DEF_SMTPD_ACL_PERM_LOG ""
extern char *var_smtpd_acl_perm_log;
+ /*
+ * Before-smtpd proxy support.
+ */
+#define VAR_SMTPD_UPROXY_PROTO "smtpd_upstream_proxy_protocol"
+#define DEF_SMTPD_UPROXY_PROTO ""
+extern char *var_smtpd_uproxy_proto;
+
+#define VAR_SMTPD_UPROXY_TMOUT "smtpd_upstream_proxy_timeout"
+#define DEF_SMTPD_UPROXY_TMOUT "5s"
+extern int var_smtpd_uproxy_tmout;
+
/*
* Postfix sendmail command compatibility features.
*/
#define MAIL_ATTR_ACT_REVERSE_CLIENT_NAME "reverse_client_name"
#define MAIL_ATTR_ACT_FORWARD_CLIENT_NAME "forward_client_name"
+#define MAIL_ATTR_ACT_SERVER_ADDR "server_address" /* server address */
+#define MAIL_ATTR_ACT_SERVER_PORT "server_port" /* server TCP port */
+
#define MAIL_ATTR_PROTO_STATE "protocol_state" /* MAIL/RCPT/... */
#define MAIL_ATTR_ORG_NONE "unknown" /* origin unknown */
#define MAIL_ATTR_ORG_LOCAL "local" /* local submission */
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20120617"
+#define MAIL_RELEASE_DATE "20120621"
#define MAIL_VERSION_NUMBER "2.10"
#ifdef SNAPSHOT
event_server.o: ../../include/debug_process.h
event_server.o: ../../include/dict.h
event_server.o: ../../include/events.h
+event_server.o: ../../include/htable.h
event_server.o: ../../include/iostuff.h
event_server.o: ../../include/listen.h
event_server.o: ../../include/mail_conf.h
master_flow.o: master.h
master_flow.o: master_flow.c
master_flow.o: master_proto.h
+master_listen.o: ../../include/htable.h
master_listen.o: ../../include/inet_addr_list.h
master_listen.o: ../../include/iostuff.h
master_listen.o: ../../include/listen.h
multi_server.o: ../../include/debug_process.h
multi_server.o: ../../include/dict.h
multi_server.o: ../../include/events.h
+multi_server.o: ../../include/htable.h
multi_server.o: ../../include/iostuff.h
multi_server.o: ../../include/listen.h
multi_server.o: ../../include/mail_conf.h
single_server.o: ../../include/debug_process.h
single_server.o: ../../include/dict.h
single_server.o: ../../include/events.h
+single_server.o: ../../include/htable.h
single_server.o: ../../include/iostuff.h
single_server.o: ../../include/listen.h
single_server.o: ../../include/mail_conf.h
trigger_server.o: ../../include/debug_process.h
trigger_server.o: ../../include/dict.h
trigger_server.o: ../../include/events.h
+trigger_server.o: ../../include/htable.h
trigger_server.o: ../../include/iostuff.h
trigger_server.o: ../../include/listen.h
trigger_server.o: ../../include/mail_conf.h
/* its privileges. The application is responsible for managing
/* subsequent I/O events on the stream, and is responsible for
/* calling event_server_disconnect() when the stream is closed.
-/* The stream initial state is non-blocking mode. The service
+/* The stream initial state is non-blocking mode.
+/* Optional connection attributes are provided as a hash that
+/* is attached as stream context. NOTE: the attributes are
+/* destroyed after this function is called. The service
/* name argument corresponds to the service name in the master.cf
/* file. The argv argument specifies command-line arguments
/* left over after options processing.
static void (*event_server_pre_disconn) (VSTREAM *, char *, char **);
static void (*event_server_slow_exit) (char *, char **);
static int event_server_watchdog = 1000;
+static int event_server_saved_flags;
/* event_server_exit - normal termination */
static void event_server_execute(int unused_event, char *context)
{
VSTREAM *stream = (VSTREAM *) context;
+ HTABLE *attr = (vstream_flags(stream) == event_server_saved_flags ?
+ (HTABLE *) vstream_context(stream) : 0);
if (event_server_lock != 0
&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
event_server_service(stream, event_server_name, event_server_argv);
if (master_notify(var_pid, event_server_generation, MASTER_STAT_AVAIL) < 0)
event_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
+ if (attr)
+ htable_free(attr, myfree);
}
/* event_server_wakeup - wake up application */
-static void event_server_wakeup(int fd)
+static void event_server_wakeup(int fd, HTABLE *attr)
{
VSTREAM *stream;
char *tmp;
client_count++;
stream = vstream_fdopen(fd, O_RDWR);
tmp = concatenate(event_server_name, " socket", (char *) 0);
- vstream_control(stream, VSTREAM_CTL_PATH, tmp, VSTREAM_CTL_END);
+ vstream_control(stream,
+ VSTREAM_CTL_PATH, tmp,
+ VSTREAM_CTL_CONTEXT, (char *) attr,
+ VSTREAM_CTL_END);
myfree(tmp);
timed_ipc_setup(stream);
+ event_server_saved_flags = vstream_flags(stream);
if (event_server_in_flow_delay && mail_flow_get(1) < 0)
event_request_timer(event_server_execute, (char *) stream,
var_in_flow_delay);
event_request_timer(event_server_timeout, (char *) 0, time_left);
return;
}
- event_server_wakeup(fd);
+ event_server_wakeup(fd, (HTABLE *) 0);
}
#ifdef MASTER_XPORT_NAME_PASS
int listen_fd = CAST_CHAR_PTR_TO_INT(context);
int time_left = -1;
int fd;
+ HTABLE *attr = 0;
/*
* Be prepared for accept() to fail because some other process already
if (event_server_pre_accept)
event_server_pre_accept(event_server_name, event_server_argv);
- fd = PASS_ACCEPT(listen_fd);
+ fd = pass_accept_attr(listen_fd, &attr);
if (event_server_lock != 0
&& myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
MYFLOCK_OP_NONE) < 0)
event_request_timer(event_server_timeout, (char *) 0, time_left);
return;
}
- event_server_wakeup(fd);
+ event_server_wakeup(fd, attr);
}
#endif
event_request_timer(event_server_timeout, (char *) 0, time_left);
return;
}
- event_server_wakeup(fd);
+ event_server_wakeup(fd, (HTABLE *) 0);
}
/* event_server_main - the real main program */
case MASTER_SERV_TYPE_PASS:
set_eugid(var_owner_uid, var_owner_gid);
serv->listen_fd[0] =
- PASS_LISTEN(serv->name, serv->max_proc > var_proc_limit ?
+ LOCAL_LISTEN(serv->name, serv->max_proc > var_proc_limit ?
serv->max_proc : var_proc_limit, NON_BLOCKING);
close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC);
set_ugid(getuid(), getgid());
break;
#ifdef MASTER_SERV_TYPE_PASS
case MASTER_SERV_TYPE_PASS:
- status = PASS_TRIGGER(serv->name, &wakeup, sizeof(wakeup), BRIEFLY);
+ status = pass_trigger(serv->name, &wakeup, sizeof(wakeup), BRIEFLY);
break;
#endif
/* function is run after the program has optionally dropped its
/* privileges. This function should not attempt to preserve state
/* across calls. The stream initial state is non-blocking mode.
+/* Optional connection attributes are provided as a hash that
+/* is attached as stream context. NOTE: the attributes are
+/* destroyed after this function is called.
/* The service name argument corresponds to the service name in the
/* master.cf file.
/* The argv argument specifies command-line arguments left over
static int multi_server_in_flow_delay;
static unsigned multi_server_generation;
static void (*multi_server_pre_disconn) (VSTREAM *, char *, char **);
+static int multi_server_saved_flags;
/* multi_server_exit - normal termination */
static void multi_server_execute(int unused_event, char *context)
{
VSTREAM *stream = (VSTREAM *) context;
+ HTABLE *attr = (vstream_flags(stream) == multi_server_saved_flags ?
+ (HTABLE *) vstream_context(stream) : 0);
if (multi_server_lock != 0
&& myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK,
} else {
multi_server_disconnect(stream);
}
+ if (attr)
+ htable_free(attr, myfree);
}
/* multi_server_enable_read - enable read events */
/* multi_server_wakeup - wake up application */
-static void multi_server_wakeup(int fd)
+static void multi_server_wakeup(int fd, HTABLE *attr)
{
VSTREAM *stream;
char *tmp;
client_count++;
stream = vstream_fdopen(fd, O_RDWR);
tmp = concatenate(multi_server_name, " socket", (char *) 0);
- vstream_control(stream, VSTREAM_CTL_PATH, tmp, VSTREAM_CTL_END);
+ vstream_control(stream,
+ VSTREAM_CTL_PATH, tmp,
+ VSTREAM_CTL_CONTEXT, (char *) attr,
+ VSTREAM_CTL_END);
myfree(tmp);
timed_ipc_setup(stream);
+ multi_server_saved_flags = vstream_flags(stream);
if (multi_server_in_flow_delay && mail_flow_get(1) < 0)
event_request_timer(multi_server_enable_read, (char *) stream,
var_in_flow_delay);
event_request_timer(multi_server_timeout, (char *) 0, time_left);
return;
}
- multi_server_wakeup(fd);
+ multi_server_wakeup(fd, (HTABLE *) 0);
}
#ifdef MASTER_XPORT_NAME_PASS
int listen_fd = CAST_CHAR_PTR_TO_INT(context);
int time_left = -1;
int fd;
+ HTABLE *attr = 0;
/*
* Be prepared for accept() to fail because some other process already
if (multi_server_pre_accept)
multi_server_pre_accept(multi_server_name, multi_server_argv);
- fd = PASS_ACCEPT(listen_fd);
+ fd = pass_accept_attr(listen_fd, &attr);
if (multi_server_lock != 0
&& myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK,
MYFLOCK_OP_NONE) < 0)
event_request_timer(multi_server_timeout, (char *) 0, time_left);
return;
}
- multi_server_wakeup(fd);
+ multi_server_wakeup(fd, attr);
}
#endif
event_request_timer(multi_server_timeout, (char *) 0, time_left);
return;
}
- multi_server_wakeup(fd);
+ multi_server_wakeup(fd, (HTABLE *) 0);
}
/* multi_server_main - the real main program */
/* a client connects to the program's service port. The function is
/* run after the program has irrevocably dropped its privileges.
/* The stream initial state is non-blocking mode.
+/* Optional connection attributes are provided as a hash that
+/* is attached as stream context.
/* The service name argument corresponds to the service name in the
/* master.cf file.
/* The argv argument specifies command-line arguments left over
/* single_server_wakeup - wake up application */
-static void single_server_wakeup(int fd)
+static void single_server_wakeup(int fd, HTABLE *attr)
{
VSTREAM *stream;
char *tmp;
close_on_exec(fd, CLOSE_ON_EXEC);
stream = vstream_fdopen(fd, O_RDWR);
tmp = concatenate(single_server_name, " socket", (char *) 0);
- vstream_control(stream, VSTREAM_CTL_PATH, tmp, VSTREAM_CTL_END);
+ vstream_control(stream,
+ VSTREAM_CTL_PATH, tmp,
+ VSTREAM_CTL_CONTEXT, (char *) attr,
+ VSTREAM_CTL_END);
myfree(tmp);
timed_ipc_setup(stream);
if (master_notify(var_pid, single_server_generation, MASTER_STAT_TAKEN) < 0)
use_count++;
if (var_idle_limit > 0)
event_request_timer(single_server_timeout, (char *) 0, var_idle_limit);
+ if (attr)
+ htable_free(attr, myfree);
}
/* single_server_accept_local - accept client connection request */
event_request_timer(single_server_timeout, (char *) 0, time_left);
return;
}
- single_server_wakeup(fd);
+ single_server_wakeup(fd, (HTABLE *) 0);
}
#ifdef MASTER_XPORT_NAME_PASS
int listen_fd = CAST_CHAR_PTR_TO_INT(context);
int time_left = -1;
int fd;
+ HTABLE *attr = 0;
/*
* Be prepared for accept() to fail because some other process already
if (single_server_pre_accept)
single_server_pre_accept(single_server_name, single_server_argv);
- fd = PASS_ACCEPT(listen_fd);
+ fd = pass_accept_attr(listen_fd, &attr);
if (single_server_lock != 0
&& myflock(vstream_fileno(single_server_lock), INTERNAL_LOCK,
MYFLOCK_OP_NONE) < 0)
event_request_timer(single_server_timeout, (char *) 0, time_left);
return;
}
- single_server_wakeup(fd);
+ single_server_wakeup(fd, attr);
}
#endif
event_request_timer(single_server_timeout, (char *) 0, time_left);
return;
}
- single_server_wakeup(fd);
+ single_server_wakeup(fd, (HTABLE *) 0);
}
/* single_server_main - the real main program */
* Register dictionaries that use higher-level interfaces and protocols.
*/
mail_dict_init();
-
+
/*
* After database open error, continue execution with reduced
* functionality.
if (trigger_server_pre_accept)
trigger_server_pre_accept(trigger_server_name, trigger_server_argv);
- fd = PASS_ACCEPT(listen_fd);
+ fd = pass_accept(listen_fd);
if (trigger_server_lock != 0
&& myflock(vstream_fileno(trigger_server_lock), INTERNAL_LOCK,
MYFLOCK_OP_NONE) < 0)
SRCS = postscreen.c postscreen_dict.c postscreen_dnsbl.c \
postscreen_early.c postscreen_smtpd.c postscreen_misc.c \
postscreen_state.c postscreen_tests.c postscreen_send.c \
- postscreen_starttls.c postscreen_expand.c
+ postscreen_starttls.c postscreen_expand.c postscreen_endpt.c \
+ postscreen_haproxy.c
OBJS = postscreen.o postscreen_dict.o postscreen_dnsbl.o \
postscreen_early.o postscreen_smtpd.o postscreen_misc.o \
postscreen_state.o postscreen_tests.o postscreen_send.o \
- postscreen_starttls.o postscreen_expand.o
+ postscreen_starttls.o postscreen_expand.o postscreen_endpt.o \
+ postscreen_haproxy.o
HDRS =
TESTSRC =
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
postscreen_dict.o: ../../include/maps.h
postscreen_dict.o: ../../include/match_list.h
postscreen_dict.o: ../../include/msg.h
+postscreen_dict.o: ../../include/myaddrinfo.h
postscreen_dict.o: ../../include/server_acl.h
postscreen_dict.o: ../../include/string_list.h
postscreen_dict.o: ../../include/sys_defs.h
postscreen_early.o: ../../include/maps.h
postscreen_early.o: ../../include/match_list.h
postscreen_early.o: ../../include/msg.h
+postscreen_early.o: ../../include/myaddrinfo.h
postscreen_early.o: ../../include/mymalloc.h
postscreen_early.o: ../../include/server_acl.h
postscreen_early.o: ../../include/string_list.h
postscreen_early.o: ../../include/vstring.h
postscreen_early.o: postscreen.h
postscreen_early.o: postscreen_early.c
+postscreen_endpt.o: ../../include/addr_match_list.h
+postscreen_endpt.o: ../../include/argv.h
+postscreen_endpt.o: ../../include/dict.h
+postscreen_endpt.o: ../../include/dict_cache.h
+postscreen_endpt.o: ../../include/events.h
+postscreen_endpt.o: ../../include/haproxy_srvr.h
+postscreen_endpt.o: ../../include/htable.h
+postscreen_endpt.o: ../../include/mail_params.h
+postscreen_endpt.o: ../../include/maps.h
+postscreen_endpt.o: ../../include/match_list.h
+postscreen_endpt.o: ../../include/msg.h
+postscreen_endpt.o: ../../include/myaddrinfo.h
+postscreen_endpt.o: ../../include/server_acl.h
+postscreen_endpt.o: ../../include/string_list.h
+postscreen_endpt.o: ../../include/sys_defs.h
+postscreen_endpt.o: ../../include/vbuf.h
+postscreen_endpt.o: ../../include/vstream.h
+postscreen_endpt.o: ../../include/vstring.h
+postscreen_endpt.o: postscreen.h
+postscreen_endpt.o: postscreen_endpt.c
+postscreen_endpt.o: postscreen_haproxy.h
postscreen_expand.o: ../../include/addr_match_list.h
postscreen_expand.o: ../../include/argv.h
postscreen_expand.o: ../../include/attr.h
postscreen_expand.o: ../../include/maps.h
postscreen_expand.o: ../../include/match_list.h
postscreen_expand.o: ../../include/msg.h
+postscreen_expand.o: ../../include/myaddrinfo.h
postscreen_expand.o: ../../include/server_acl.h
postscreen_expand.o: ../../include/string_list.h
postscreen_expand.o: ../../include/stringops.h
postscreen_expand.o: ../../include/vstring.h
postscreen_expand.o: postscreen.h
postscreen_expand.o: postscreen_expand.c
+postscreen_haproxy.o: ../../include/addr_match_list.h
+postscreen_haproxy.o: ../../include/argv.h
+postscreen_haproxy.o: ../../include/dict.h
+postscreen_haproxy.o: ../../include/dict_cache.h
+postscreen_haproxy.o: ../../include/events.h
+postscreen_haproxy.o: ../../include/haproxy_srvr.h
+postscreen_haproxy.o: ../../include/htable.h
+postscreen_haproxy.o: ../../include/maps.h
+postscreen_haproxy.o: ../../include/match_list.h
+postscreen_haproxy.o: ../../include/msg.h
+postscreen_haproxy.o: ../../include/myaddrinfo.h
+postscreen_haproxy.o: ../../include/mymalloc.h
+postscreen_haproxy.o: ../../include/server_acl.h
+postscreen_haproxy.o: ../../include/string_list.h
+postscreen_haproxy.o: ../../include/stringops.h
+postscreen_haproxy.o: ../../include/sys_defs.h
+postscreen_haproxy.o: ../../include/vbuf.h
+postscreen_haproxy.o: ../../include/vstream.h
+postscreen_haproxy.o: ../../include/vstring.h
+postscreen_haproxy.o: postscreen.h
+postscreen_haproxy.o: postscreen_haproxy.c
+postscreen_haproxy.o: postscreen_haproxy.h
postscreen_misc.o: ../../include/addr_match_list.h
postscreen_misc.o: ../../include/argv.h
postscreen_misc.o: ../../include/dict.h
postscreen_misc.o: ../../include/maps.h
postscreen_misc.o: ../../include/match_list.h
postscreen_misc.o: ../../include/msg.h
+postscreen_misc.o: ../../include/myaddrinfo.h
postscreen_misc.o: ../../include/server_acl.h
postscreen_misc.o: ../../include/string_list.h
postscreen_misc.o: ../../include/sys_defs.h
postscreen_misc.o: postscreen_misc.c
postscreen_send.o: ../../include/addr_match_list.h
postscreen_send.o: ../../include/argv.h
+postscreen_send.o: ../../include/attr.h
postscreen_send.o: ../../include/connect.h
postscreen_send.o: ../../include/dict.h
postscreen_send.o: ../../include/dict_cache.h
postscreen_send.o: ../../include/mac_expand.h
postscreen_send.o: ../../include/mac_parse.h
postscreen_send.o: ../../include/mail_params.h
+postscreen_send.o: ../../include/mail_proto.h
postscreen_send.o: ../../include/maps.h
postscreen_send.o: ../../include/match_list.h
postscreen_send.o: ../../include/msg.h
+postscreen_send.o: ../../include/myaddrinfo.h
postscreen_send.o: ../../include/server_acl.h
postscreen_send.o: ../../include/smtp_reply_footer.h
postscreen_send.o: ../../include/string_list.h
postscreen_smtpd.o: ../../include/maps.h
postscreen_smtpd.o: ../../include/match_list.h
postscreen_smtpd.o: ../../include/msg.h
+postscreen_smtpd.o: ../../include/myaddrinfo.h
postscreen_smtpd.o: ../../include/mymalloc.h
postscreen_smtpd.o: ../../include/name_code.h
postscreen_smtpd.o: ../../include/name_mask.h
postscreen_starttls.o: ../../include/maps.h
postscreen_starttls.o: ../../include/match_list.h
postscreen_starttls.o: ../../include/msg.h
+postscreen_starttls.o: ../../include/myaddrinfo.h
postscreen_starttls.o: ../../include/mymalloc.h
postscreen_starttls.o: ../../include/name_code.h
postscreen_starttls.o: ../../include/name_mask.h
postscreen_state.o: ../../include/maps.h
postscreen_state.o: ../../include/match_list.h
postscreen_state.o: ../../include/msg.h
+postscreen_state.o: ../../include/myaddrinfo.h
postscreen_state.o: ../../include/mymalloc.h
postscreen_state.o: ../../include/name_mask.h
postscreen_state.o: ../../include/server_acl.h
postscreen_tests.o: ../../include/maps.h
postscreen_tests.o: ../../include/match_list.h
postscreen_tests.o: ../../include/msg.h
+postscreen_tests.o: ../../include/myaddrinfo.h
postscreen_tests.o: ../../include/server_acl.h
postscreen_tests.o: ../../include/string_list.h
postscreen_tests.o: ../../include/sys_defs.h
/* .IP "\fBsoft_bounce (no)\fR"
/* Safety net to keep mail queued that would otherwise be returned to
/* the sender.
+/* BEFORE-POSTSCREEN PROXY AGENT
+/* .ad
+/* .fi
+/* Available in Postfix version 2.10 and later:
+/* .IP "\fBpostscreen_upstream_proxy_protocol (empty)\fR"
+/* The name of the proxy protocol used by an optional before-postscreen
+/* proxy agent.
+/* .IP "\fBpostscreen_upstream_proxy_timeout (5s)\fR"
+/* The time limit for the proxy protocol specified with the
+/* postscreen_upstream_proxy_protocol parameter.
/* PERMANENT WHITE/BLACKLIST TEST
/* .ad
/* .fi
char *var_psc_exp_filter;
char *var_psc_wlist_if;
+char *var_psc_uproxy_proto;
+int var_psc_uproxy_tmout;
/*
* Global variables.
HTABLE *psc_client_concurrency; /* per-client concurrency */
/*
- * Local variables.
+ * Local variables and functions.
*/
static ARGV *psc_acl; /* permanent white/backlist */
static int psc_blist_action; /* PSC_ACT_DROP/ENFORCE/etc */
static ADDR_MATCH_LIST *psc_wlist_if; /* whitelist interfaces */
+static void psc_endpt_lookup_done(int, VSTREAM *,
+ MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *,
+ MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *);
+
/* psc_dump - dump some statistics before exit */
static void psc_dump(void)
char *unused_service,
char **unused_argv)
{
- const char *myname = "psc_service";
- PSC_STATE *state;
- struct sockaddr_storage addr_storage;
- SOCKADDR_SIZE addr_storage_len = sizeof(addr_storage);
- MAI_HOSTADDR_STR smtp_client_addr;
- MAI_SERVPORT_STR smtp_client_port;
- MAI_HOSTADDR_STR smtp_server_addr;
- MAI_SERVPORT_STR smtp_server_port;
- int aierr;
- const char *stamp_str;
- int saved_flags;
/*
* For sanity, require that at least one of INET or INET6 is enabled.
non_blocking(vstream_fileno(smtp_client_stream), NON_BLOCKING);
/*
- * We use the event_server framework. This means we get already-accepted
- * connections so we have to invoke getpeername() to find out the remote
- * address and port.
+ * Look up the remote SMTP client address and port.
*/
+ psc_endpt_lookup(smtp_client_stream, psc_endpt_lookup_done);
+}
- /* Best effort - if this non-blocking write(2) fails, so be it. */
-#define PSC_SERVICE_DISCONNECT_AND_RETURN(stream) do { \
- (void) write(vstream_fileno(stream), \
- "421 4.3.2 No system resources\r\n", \
- sizeof("421 4.3.2 No system resources\r\n") - 1); \
- event_server_disconnect(stream); \
- return; \
- } while (0);
+/* psc_endpt_lookup_done - endpoint lookup completed */
- /*
- * Look up the remote SMTP client address and port.
- */
- if (getpeername(vstream_fileno(smtp_client_stream), (struct sockaddr *)
- & addr_storage, &addr_storage_len) < 0) {
- msg_warn("getpeername: %m -- dropping this connection");
- PSC_SERVICE_DISCONNECT_AND_RETURN(smtp_client_stream);
- }
+static void psc_endpt_lookup_done(int endpt_status,
+ VSTREAM *smtp_client_stream,
+ MAI_HOSTADDR_STR *smtp_client_addr,
+ MAI_SERVPORT_STR *smtp_client_port,
+ MAI_HOSTADDR_STR *smtp_server_addr,
+ MAI_SERVPORT_STR *smtp_server_port)
+{
+ const char *myname = "psc_endpt_lookup_done";
+ PSC_STATE *state;
+ const char *stamp_str;
+ int saved_flags;
/*
- * Convert the remote SMTP client address and port to printable form for
- * logging and access control.
+ * Best effort - if this non-blocking write(2) fails, so be it.
*/
- if ((aierr = sockaddr_to_hostaddr((struct sockaddr *) & addr_storage,
- addr_storage_len, &smtp_client_addr,
- &smtp_client_port, 0)) != 0) {
- msg_warn("cannot convert client address/port to string: %s"
- " -- dropping this connection",
- MAI_STRERROR(aierr));
- PSC_SERVICE_DISCONNECT_AND_RETURN(smtp_client_stream);
+ if (endpt_status < 0) {
+ (void) write(vstream_fileno(smtp_client_stream),
+ "421 4.3.2 No system resources\r\n",
+ sizeof("421 4.3.2 No system resources\r\n") - 1);
+ event_server_disconnect(smtp_client_stream);
+ return;
}
- if (strncasecmp("::ffff:", smtp_client_addr.buf, 7) == 0)
- memmove(smtp_client_addr.buf, smtp_client_addr.buf + 7,
- sizeof(smtp_client_addr.buf) - 7);
if (msg_verbose > 1)
msg_info("%s: sq=%d cq=%d connect from [%s]:%s",
myname, psc_post_queue_length, psc_check_queue_length,
- smtp_client_addr.buf, smtp_client_port.buf);
-
- /*
- * Look up the local SMTP server address and port.
- */
- if (getsockname(vstream_fileno(smtp_client_stream), (struct sockaddr *)
- & addr_storage, &addr_storage_len) < 0) {
- msg_warn("getsockname: %m -- dropping this connection");
- PSC_SERVICE_DISCONNECT_AND_RETURN(smtp_client_stream);
- }
-
- /*
- * Convert the local SMTP server address and port to printable form for
- * logging and access control.
- */
- if ((aierr = sockaddr_to_hostaddr((struct sockaddr *) & addr_storage,
- addr_storage_len, &smtp_server_addr,
- &smtp_server_port, 0)) != 0) {
- msg_warn("cannot convert server address/port to string: %s"
- " -- dropping this connection",
- MAI_STRERROR(aierr));
- PSC_SERVICE_DISCONNECT_AND_RETURN(smtp_client_stream);
- }
- if (strncasecmp("::ffff:", smtp_server_addr.buf, 7) == 0)
- memmove(smtp_server_addr.buf, smtp_server_addr.buf + 7,
- sizeof(smtp_server_addr.buf) - 7);
+ smtp_client_addr->buf, smtp_client_port->buf);
msg_info("CONNECT from [%s]:%s to [%s]:%s",
- smtp_client_addr.buf, smtp_client_port.buf,
- smtp_server_addr.buf, smtp_server_port.buf);
+ smtp_client_addr->buf, smtp_client_port->buf,
+ smtp_server_addr->buf, smtp_server_port->buf);
/*
* Bundle up all the loose session pieces. This zeroes all flags and time
* stamps.
*/
- state = psc_new_session_state(smtp_client_stream, smtp_client_addr.buf,
- smtp_client_port.buf);
+ state = psc_new_session_state(smtp_client_stream, smtp_client_addr->buf,
+ smtp_client_port->buf,
+ smtp_server_addr->buf,
+ smtp_server_port->buf);
/*
* Reply with 421 when the client has too many open connections.
* Don't whitelist clients that connect to backup MX addresses. Fail
* "closed" on error.
*/
- if (addr_match_list_match(psc_wlist_if, smtp_server_addr.buf) == 0) {
+ if (addr_match_list_match(psc_wlist_if, smtp_server_addr->buf) == 0) {
state->flags |= (PSC_STATE_FLAG_WLIST_FAIL | PSC_STATE_FLAG_NOFORWARD);
msg_info("WHITELIST VETO [%s]:%s", PSC_CLIENT_ADDR_PORT(state));
}
VAR_DNSBLOG_SERVICE, DEF_DNSBLOG_SERVICE, &var_dnsblog_service, 1, 0,
VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0,
VAR_PSC_WLIST_IF, DEF_PSC_WLIST_IF, &var_psc_wlist_if, 0, 0,
+ VAR_PSC_UPROXY_PROTO, DEF_PSC_UPROXY_PROTO, &var_psc_uproxy_proto, 0, 0,
0,
};
static const CONFIG_INT_TABLE int_table[] = {
VAR_PSC_CACHE_RET, DEF_PSC_CACHE_RET, &var_psc_cache_ret, 1, 0,
VAR_PSC_CACHE_SCAN, DEF_PSC_CACHE_SCAN, &var_psc_cache_scan, 0, 0,
VAR_PSC_WATCHDOG, DEF_PSC_WATCHDOG, &var_psc_watchdog, 10, 0,
+ VAR_PSC_UPROXY_TMOUT, DEF_PSC_UPROXY_TMOUT, &var_psc_uproxy_tmout, 1, 0,
0,
};
static const CONFIG_BOOL_TABLE bool_table[] = {
#include <vstring.h>
#include <events.h>
#include <htable.h>
+#include <myaddrinfo.h>
/*
* Global library.
int smtp_server_fd; /* real SMTP server */
char *smtp_client_addr; /* client address */
char *smtp_client_port; /* client port */
+ char *smtp_server_addr; /* server address */
+ char *smtp_server_port; /* server port */
int client_concurrency; /* per-client */
const char *final_reply; /* cause for hanging up */
VSTRING *send_buf; /* pending output */
(state)->smtp_client_stream = 0; \
psc_check_queue_length--; \
} while (0)
-extern PSC_STATE *psc_new_session_state(VSTREAM *, const char *, const char *);
+extern PSC_STATE *psc_new_session_state(VSTREAM *, const char *, const char *, const char *, const char *);
extern void psc_free_session_state(PSC_STATE *);
extern const char *psc_print_state_flags(int, const char *);
extern void psc_expand_init(void);
extern const char *psc_expand_lookup(const char *, int, char *);
+ /*
+ * postscreen_endpt.c
+ */
+typedef void (*PSC_ENDPT_LOOKUP_FN) (int, VSTREAM *,
+ MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *,
+ MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *);
+extern void psc_endpt_lookup(VSTREAM *, PSC_ENDPT_LOOKUP_FN);
+
/*
* postscreen_access emulation.
*/
--- /dev/null
+/*++
+/* NAME
+/* postscreen_endpt 3
+/* SUMMARY
+/* look up connection endpoint information
+/* SYNOPSIS
+/* #include <postscreen.h>
+/*
+/* void psc_endpt_lookup(smtp_client_stream,
+/* void *lookup_done(status, smtp_client_stream,
+/* smtp_client_addr, smtp_client_port,
+/* smtp_server_addr, smtp_server_port))
+/* VSTRING *smtp_client_stream;
+/* int status;
+/* MAI_HOSTADDR_STR *smtp_client_addr;
+/* MAI_SERVPORT_STR *smtp_client_port;
+/* MAI_HOSTADDR_STR *smtp_server_addr;
+/* MAI_SERVPORT_STR *smtp_server_port;
+/* DESCRIPTION
+/* psc_endpt_lookup() looks up remote and local connection
+/* endpoint information through local system calls or through
+/* a remote proxy protocol. The lookup_done() call-back routine
+/* passes the result status, address and port information. The
+/* result status is -1 in case of error, 0 in case of success.
+/* This function (and its supporting routines) logs a warning
+/* in case of error, and never communicates with a remote SMTP
+/* client.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <string.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <myaddrinfo.h>
+#include <vstream.h>
+#include <inet_proto.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <haproxy_srvr.h>
+
+/* Application-specific. */
+
+#include <postscreen.h>
+#include <postscreen_haproxy.h>
+
+static INET_PROTO_INFO *proto_info;
+
+/* psc_sockaddr_to_hostaddr - transform endpoint address and port to string */
+
+static int psc_sockaddr_to_hostaddr(struct sockaddr * addr_storage,
+ SOCKADDR_SIZE addr_storage_len,
+ MAI_HOSTADDR_STR *addr_buf,
+ MAI_SERVPORT_STR *port_buf,
+ int socktype)
+{
+ int aierr;
+
+ if ((aierr = sockaddr_to_hostaddr(addr_storage, addr_storage_len,
+ addr_buf, port_buf, socktype)) == 0
+ && strncasecmp("::ffff:", addr_buf->buf, 7) == 0
+ && strchr((char *) proto_info->sa_family_list, AF_INET) != 0)
+ memmove(addr_buf->buf, addr_buf->buf + 7,
+ sizeof(addr_buf->buf) - 7);
+ return (aierr);
+}
+
+/* psc_endpt_local_lookup - look up local system connection information */
+
+static void psc_endpt_local_lookup(VSTREAM *smtp_client_stream,
+ PSC_ENDPT_LOOKUP_FN lookup_done)
+{
+ struct sockaddr_storage addr_storage;
+ SOCKADDR_SIZE addr_storage_len = sizeof(addr_storage);
+ int status;
+ MAI_HOSTADDR_STR smtp_client_addr;
+ MAI_SERVPORT_STR smtp_client_port;
+ MAI_HOSTADDR_STR smtp_server_addr;
+ MAI_SERVPORT_STR smtp_server_port;
+ int aierr;
+
+ /*
+ * Look up the remote SMTP client address and port.
+ */
+ if (getpeername(vstream_fileno(smtp_client_stream), (struct sockaddr *)
+ & addr_storage, &addr_storage_len) < 0) {
+ msg_warn("getpeername: %m -- dropping this connection");
+ status = -1;
+ }
+
+ /*
+ * Convert the remote SMTP client address and port to printable form for
+ * logging and access control.
+ */
+ else if ((aierr = psc_sockaddr_to_hostaddr(
+ (struct sockaddr *) & addr_storage,
+ addr_storage_len, &smtp_client_addr,
+ &smtp_client_port, SOCK_STREAM)) != 0) {
+ msg_warn("cannot convert client address/port to string: %s"
+ " -- dropping this connection",
+ MAI_STRERROR(aierr));
+ status = -1;
+ }
+
+ /*
+ * Look up the local SMTP server address and port.
+ */
+ else if (getsockname(vstream_fileno(smtp_client_stream),
+ (struct sockaddr *) & addr_storage,
+ &addr_storage_len) < 0) {
+ msg_warn("getsockname: %m -- dropping this connection");
+ status = -1;
+ }
+
+ /*
+ * Convert the local SMTP server address and port to printable form for
+ * logging.
+ */
+ else if ((aierr = psc_sockaddr_to_hostaddr(
+ (struct sockaddr *) & addr_storage,
+ addr_storage_len, &smtp_server_addr,
+ &smtp_server_port, SOCK_STREAM)) != 0) {
+ msg_warn("cannot convert server address/port to string: %s"
+ " -- dropping this connection",
+ MAI_STRERROR(aierr));
+ status = -1;
+ } else {
+ status = 0;
+ }
+ lookup_done(status, smtp_client_stream,
+ &smtp_client_addr, &smtp_client_port,
+ &smtp_server_addr, &smtp_server_port);
+}
+
+ /*
+ * Lookup table for available proxy protocols.
+ */
+typedef struct {
+ const char *name;
+ void (*endpt_lookup) (VSTREAM *, PSC_ENDPT_LOOKUP_FN);
+} PSC_ENDPT_LOOKUP_INFO;
+
+static const PSC_ENDPT_LOOKUP_INFO psc_endpt_lookup_info[] = {
+ DEF_PSC_UPROXY_PROTO, psc_endpt_local_lookup,
+ HAPROXY_PROTO_NAME, psc_endpt_haproxy_lookup,
+ 0,
+};
+
+/* psc_endpt_lookup - look up connection endpoint information */
+
+void psc_endpt_lookup(VSTREAM *smtp_client_stream,
+ PSC_ENDPT_LOOKUP_FN notify)
+{
+ const PSC_ENDPT_LOOKUP_INFO *pp;
+
+ if (proto_info == 0)
+ proto_info = inet_proto_info();
+
+ for (pp = psc_endpt_lookup_info; /* see below */ ; pp++) {
+ if (pp->name == 0)
+ msg_fatal("unsupported %s value: %s",
+ VAR_PSC_UPROXY_PROTO, var_psc_uproxy_proto);
+ if (strcmp(var_psc_uproxy_proto, pp->name) == 0) {
+ pp->endpt_lookup(smtp_client_stream, notify);
+ return;
+ }
+ }
+}
--- /dev/null
+/*++
+/* NAME
+/* postscreen_haproxy 3
+/* SUMMARY
+/* haproxy protocol adapter
+/* SYNOPSIS
+/* #include <postscreen_haproxy.h>
+/*
+/* void psc_endpt_haproxy_lookup(smtp_client_stream,
+/* void *lookup_done(status, smtp_client_stream,
+/* smtp_client_addr, smtp_client_port,
+/* smtp_server_addr, smtp_server_port))
+/* VSTRING *smtp_client_stream;
+/* int status;
+/* MAI_HOSTADDR_STR *smtp_client_addr;
+/* MAI_SERVPORT_STR *smtp_client_port;
+/* MAI_HOSTADDR_STR *smtp_server_addr;
+/* MAI_SERVPORT_STR *smtp_server_port;
+/* DESCRIPTION
+/* psc_endpt_haproxy_lookup() looks up connection endpoint
+/* information via the haproxy protocol. Arguments and results
+/* conform to the postscreen_endpt(3) API.
+/*
+/* The following summarizes what the Postfix SMTP server expects
+/* from an up-stream proxy adapter.
+/* .IP \(bu
+/* Validate address and port syntax. Permit only protocols
+/* that are configured with the main.cf:inet_protocols
+/* setting.
+/* .IP \(bu
+/* Convert IPv4-in-IPv6 address syntax to IPv4 form, when both
+/* IPv4 and IPv6 support are enabled with main.cf:inet_protocols.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <events.h>
+#include <myaddrinfo.h>
+#include <vstream.h>
+#include <vstring.h>
+#include <stringops.h>
+
+/* Global library. */
+
+#include <haproxy_srvr.h>
+#include <mail_params.h>
+
+/* Application-specific. */
+
+#include <postscreen.h>
+#include <postscreen_haproxy.h>
+
+ /*
+ * Per-session state.
+ */
+typedef struct {
+ VSTREAM *stream;
+ PSC_ENDPT_LOOKUP_FN notify;
+ VSTRING *buffer;
+} PSC_HAPROXY_STATE;
+
+/* psc_endpt_haproxy_event - read or time event */
+
+static void psc_endpt_haproxy_event(int event, char *context)
+{
+ const char *myname = "psc_endpt_haproxy_event";
+ PSC_HAPROXY_STATE *state = (PSC_HAPROXY_STATE *) context;
+ int status = 0;
+ MAI_HOSTADDR_STR smtp_client_addr;
+ MAI_SERVPORT_STR smtp_client_port;
+ MAI_HOSTADDR_STR smtp_server_addr;
+ MAI_SERVPORT_STR smtp_server_port;
+ int last_char = 0;
+ const char *err;
+ VSTRING *escape_buf;
+
+ /*
+ * Basic event processing.
+ */
+ switch (event) {
+ case EVENT_TIME:
+ msg_warn("haproxy read: time limit exceeded");
+ status = -1;
+ break;
+ case EVENT_READ:
+ if ((last_char = VSTREAM_GETC(state->stream)) == VSTREAM_EOF) {
+ if (vstream_ferror(state->stream))
+ msg_warn("haproxy read: %m");
+ else
+ msg_warn("haproxy read: lost connection");
+ status = -1;
+ break;
+ }
+ if (VSTRING_LEN(state->buffer) >= HAPROXY_MAX_LEN) {
+ msg_warn("haproxy read: line too long");
+ status = -1;
+ break;
+ }
+ VSTRING_ADDCH(state->buffer, last_char);
+ break;
+ }
+
+ /*
+ * Parse the haproxy line. Note: the haproxy_srvr_parse() routine
+ * performs address protocol checks, address and port syntax checks, and
+ * converts IPv4-in-IPv6 address string syntax (:ffff::1.2.3.4) to IPv4
+ * syntax where permitted by the main.cf:inet_protocols setting.
+ */
+ if (status == 0 && last_char == '\n') {
+ VSTRING_TERMINATE(state->buffer);
+ if ((err = haproxy_srvr_parse(vstring_str(state->buffer),
+ &smtp_client_addr, &smtp_client_port,
+ &smtp_server_addr, &smtp_server_port)) != 0) {
+ escape_buf = vstring_alloc(HAPROXY_MAX_LEN + 2);
+ escape(escape_buf, vstring_str(state->buffer),
+ VSTRING_LEN(state->buffer));
+ msg_warn("haproxy read: %s: %s", err, vstring_str(escape_buf));
+ status = -1;
+ vstring_free(escape_buf);
+ }
+ }
+
+ /*
+ * Are we done yet?
+ */
+ if (status < 0 || last_char == '\n') {
+ PSC_CLEAR_EVENT_REQUEST(vstream_fileno(state->stream),
+ psc_endpt_haproxy_event, context);
+ vstream_control(state->stream,
+ VSTREAM_CTL_BUFSIZE, VSTREAM_BUFSIZE,
+ VSTREAM_CTL_END);
+ state->notify(status, state->stream,
+ &smtp_client_addr, &smtp_client_port,
+ &smtp_server_addr, &smtp_server_port);
+ /* Note: the stream may be closed at this point. */
+ vstring_free(state->buffer);
+ myfree((char *) state);
+ }
+}
+
+/* psc_endpt_haproxy_lookup - event-driven haproxy client */
+
+void psc_endpt_haproxy_lookup(VSTREAM *stream,
+ PSC_ENDPT_LOOKUP_FN notify)
+{
+ const char *myname = "psc_endpt_haproxy_lookup";
+ PSC_HAPROXY_STATE *state;
+
+ /*
+ * Prepare the per-session state. XXX To improve overload behavior,
+ * maintain a pool of these so that we can reduce memory allocator
+ * activity.
+ */
+ state = (PSC_HAPROXY_STATE *) mymalloc(sizeof(*state));
+ state->stream = stream;
+ state->notify = notify;
+ state->buffer = vstring_alloc(100);
+
+ /*
+ * We don't assume that the haproxy line will be unfragmented. Therefore,
+ * we use read(2) instead of recv(..., MSG_PEEK).
+ *
+ * We must not read(2) past the <CR><LF> that terminates the haproxy line.
+ * Therefore we force one-character read(2) calls.
+ *
+ * We want to (eventually) build this on top of a reusable line read
+ * routine, once we have figured out an easy-to-use and efficient API.
+ */
+ vstream_control(stream, VSTREAM_CTL_BUFSIZE, 1, VSTREAM_CTL_END);
+
+ /*
+ * Read the haproxy line.
+ */
+ PSC_READ_EVENT_REQUEST(vstream_fileno(stream), psc_endpt_haproxy_event,
+ (char *) state, var_psc_uproxy_tmout);
+}
--- /dev/null
+/*++
+/* NAME
+/* postscreen_haproxy 3h
+/* SUMMARY
+/* postscreen haproxy protocol support
+/* SYNOPSIS
+/* #include <postscreen_haproxy.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * haproxy protocol interface.
+ */
+extern void psc_endpt_haproxy_lookup(VSTREAM *, PSC_ENDPT_LOOKUP_FN);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
#include <msg.h>
#include <iostuff.h>
#include <connect.h>
+#include <attr.h>
+#include <vstream.h>
/* Global library. */
#include <mail_params.h>
#include <smtp_reply_footer.h>
+#include <mail_proto.h>
/* Application-specific. */
{
const char *myname = "psc_send_socket";
int server_fd;
+ int pass_err;
+ VSTREAM *fp;
if (msg_verbose > 1)
msg_info("%s: sq=%d cq=%d send socket %d from [%s]:%s",
* Postfix-specific.
*/
if ((server_fd =
- PASS_CONNECT(psc_smtpd_service_name, NON_BLOCKING,
- PSC_SEND_SOCK_CONNECT_TIMEOUT)) < 0) {
+ LOCAL_CONNECT(psc_smtpd_service_name, NON_BLOCKING,
+ PSC_SEND_SOCK_CONNECT_TIMEOUT)) < 0) {
msg_warn("cannot connect to service %s: %m", psc_smtpd_service_name);
if (state->flags & PSC_STATE_FLAG_PREGR_TODO) {
PSC_SMTPD_X21(state, "421 4.3.2 No system resources\r\n");
}
return;
}
- if (LOCAL_SEND_FD(server_fd,
- vstream_fileno(state->smtp_client_stream)) < 0) {
+ /* XXX Note: no dummy read between LOCAL_SEND_FD() and attr_print(). */
+ fp = vstream_fdopen(server_fd, O_RDWR);
+ pass_err =
+ (LOCAL_SEND_FD(server_fd,
+ vstream_fileno(state->smtp_client_stream)) < 0
+ || (attr_print(fp, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_ACT_CLIENT_ADDR, state->smtp_client_addr,
+ ATTR_TYPE_STR, MAIL_ATTR_ACT_CLIENT_PORT, state->smtp_client_port,
+ ATTR_TYPE_STR, MAIL_ATTR_ACT_SERVER_ADDR, state->smtp_server_addr,
+ ATTR_TYPE_STR, MAIL_ATTR_ACT_SERVER_PORT, state->smtp_server_port,
+ ATTR_TYPE_END) || vstream_fflush(fp)));
+ (void) vstream_fdclose(fp);
+ if (pass_err != 0) {
msg_warn("cannot pass connection to service %s: %m",
psc_smtpd_service_name);
(void) close(server_fd);
/* SYNOPSIS
/* #include <postscreen.h>
/*
-/* PSC_STATE *psc_new_session_state(stream, addr, port)
+/* PSC_STATE *psc_new_session_state(stream, client_addr, client_port,
+/* server_addr, server_port)
/* VSTREAM *stream;
-/* const char *addr;
-/* const char *port;
+/* const char *client_addr;
+/* const char *client_port;
+/* const char *server_addr;
+/* const char *server_port;
/*
/* void psc_free_session_state(state)
/* PSC_STATE *state;
/* psc_new_session_state - fill in connection state for event processing */
PSC_STATE *psc_new_session_state(VSTREAM *stream,
- const char *addr,
- const char *port)
+ const char *client_addr,
+ const char *client_port,
+ const char *server_addr,
+ const char *server_port)
{
PSC_STATE *state;
HTABLE_INFO *ht;
if ((state->smtp_client_stream = stream) != 0)
psc_check_queue_length++;
state->smtp_server_fd = (-1);
- state->smtp_client_addr = mystrdup(addr);
- state->smtp_client_port = mystrdup(port);
+ state->smtp_client_addr = mystrdup(client_addr);
+ state->smtp_client_port = mystrdup(client_port);
+ state->smtp_server_addr = mystrdup(server_addr);
+ state->smtp_server_port = mystrdup(server_port);
state->send_buf = vstring_alloc(100);
state->test_name = "TEST NAME HERE";
state->dnsbl_reply = 0;
/*
* Update the per-client session count.
*/
- if ((ht = htable_locate(psc_client_concurrency, addr)) == 0)
- ht = htable_enter(psc_client_concurrency, addr, (char *) 0);
+ if ((ht = htable_locate(psc_client_concurrency, client_addr)) == 0)
+ ht = htable_enter(psc_client_concurrency, client_addr, (char *) 0);
ht->value += 1;
state->client_concurrency = CAST_CHAR_PTR_TO_INT(ht->value);
state->send_buf = vstring_free(state->send_buf);
myfree(state->smtp_client_addr);
myfree(state->smtp_client_port);
+ myfree(state->smtp_server_addr);
+ myfree(state->smtp_server_port);
if (state->dnsbl_reply)
vstring_free(state->dnsbl_reply);
if (state->helo_name)
SRCS = smtpd.c smtpd_token.c smtpd_check.c smtpd_chat.c smtpd_state.c \
smtpd_peer.c smtpd_sasl_proto.c smtpd_sasl_glue.c smtpd_proxy.c \
smtpd_xforward.c smtpd_dsn_fix.c smtpd_milter.c smtpd_resolve.c \
- smtpd_expand.c
+ smtpd_expand.c smtpd_haproxy.c
OBJS = smtpd.o smtpd_token.o smtpd_check.o smtpd_chat.o smtpd_state.o \
smtpd_peer.o smtpd_sasl_proto.o smtpd_sasl_glue.o smtpd_proxy.o \
smtpd_xforward.o smtpd_dsn_fix.o smtpd_milter.o smtpd_resolve.o \
- smtpd_expand.o
+ smtpd_expand.o smtpd_haproxy.o
HDRS = smtpd_token.h smtpd_check.h smtpd_chat.h smtpd_sasl_proto.h \
smtpd_sasl_glue.h smtpd_proxy.h smtpd_dsn_fix.h smtpd_milter.h \
smtpd_resolve.h smtpd_expand.h
smtpd_expand.o: smtpd.h
smtpd_expand.o: smtpd_expand.c
smtpd_expand.o: smtpd_expand.h
+smtpd_haproxy.o: ../../include/argv.h
+smtpd_haproxy.o: ../../include/attr.h
+smtpd_haproxy.o: ../../include/haproxy_srvr.h
+smtpd_haproxy.o: ../../include/mail_params.h
+smtpd_haproxy.o: ../../include/mail_stream.h
+smtpd_haproxy.o: ../../include/milter.h
+smtpd_haproxy.o: ../../include/msg.h
+smtpd_haproxy.o: ../../include/myaddrinfo.h
+smtpd_haproxy.o: ../../include/mymalloc.h
+smtpd_haproxy.o: ../../include/name_code.h
+smtpd_haproxy.o: ../../include/name_mask.h
+smtpd_haproxy.o: ../../include/smtp_stream.h
+smtpd_haproxy.o: ../../include/stringops.h
+smtpd_haproxy.o: ../../include/sys_defs.h
+smtpd_haproxy.o: ../../include/tls.h
+smtpd_haproxy.o: ../../include/valid_hostname.h
+smtpd_haproxy.o: ../../include/valid_mailhost_addr.h
+smtpd_haproxy.o: ../../include/vbuf.h
+smtpd_haproxy.o: ../../include/vstream.h
+smtpd_haproxy.o: ../../include/vstring.h
+smtpd_haproxy.o: smtpd.h
+smtpd_haproxy.o: smtpd_haproxy.c
smtpd_milter.o: ../../include/argv.h
smtpd_milter.o: ../../include/attr.h
smtpd_milter.o: ../../include/mail_params.h
smtpd_milter.o: smtpd_sasl_glue.h
smtpd_peer.o: ../../include/argv.h
smtpd_peer.o: ../../include/attr.h
+smtpd_peer.o: ../../include/haproxy_srvr.h
+smtpd_peer.o: ../../include/htable.h
smtpd_peer.o: ../../include/inet_proto.h
smtpd_peer.o: ../../include/iostuff.h
smtpd_peer.o: ../../include/mail_params.h
/* at all, or rewrite message headers and update incomplete addresses
/* with the domain specified in the remote_header_rewrite_domain
/* parameter.
+/* BEFORE-SMTPD PROXY AGENT
+/* .ad
+/* .fi
+/* Available in Postfix version 2.10 and later:
+/* .IP "\fBsmtpd_upstream_proxy_protocol (empty)\fR"
+/* The name of the proxy protocol used by an optional before-smtpd
+/* proxy agent.
+/* .IP "\fBsmtpd_upstream_proxy_timeout (5s)\fR"
+/* The time limit for the proxy protocol specified with the
+/* smtpd_upstream_proxy_protocol parameter.
/* AFTER QUEUE EXTERNAL CONTENT INSPECTION CONTROLS
/* .ad
/* .fi
#endif
+char *var_smtpd_uproxy_proto;
+int var_smtpd_uproxy_tmout;
+
/*
* Silly little macros.
*/
/*
* Provide the SMTP service.
*/
- smtpd_proto(&state);
+ if ((state.flags & SMTPD_FLAG_HANGUP) == 0)
+ smtpd_proto(&state);
/*
* After the client has gone away, clean up whatever we have set up at
VAR_MILT_CMD_TIME, DEF_MILT_CMD_TIME, &var_milt_cmd_time, 1, 0,
VAR_MILT_MSG_TIME, DEF_MILT_MSG_TIME, &var_milt_msg_time, 1, 0,
VAR_VERIFY_SENDER_TTL, DEF_VERIFY_SENDER_TTL, &var_verify_sender_ttl, 0, 0,
+ VAR_SMTPD_UPROXY_TMOUT, DEF_SMTPD_UPROXY_TMOUT, &var_smtpd_uproxy_tmout, 1, 0,
0,
};
static const CONFIG_BOOL_TABLE bool_table[] = {
VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0,
#endif
VAR_SMTPD_ACL_PERM_LOG, DEF_SMTPD_ACL_PERM_LOG, &var_smtpd_acl_perm_log, 0, 0,
+ VAR_SMTPD_UPROXY_PROTO, DEF_SMTPD_UPROXY_PROTO, &var_smtpd_uproxy_proto, 0, 0,
0,
};
static const CONFIG_RAW_TABLE raw_table[] = {
char *namaddr; /* name[address]:port */
char *rfc_addr; /* address for RFC 2821 */
int addr_family; /* address family */
+ char *dest_addr; /* for Dovecot AUTH */
struct sockaddr_storage sockaddr; /* binary client endpoint */
+ SOCKADDR_SIZE sockaddr_len; /* binary client endpoint */
int name_status; /* 2=ok 4=soft 5=hard 6=forged */
int reverse_name_status; /* 2=ok 4=soft 5=hard */
int conn_count; /* connections from this client */
*/
extern void smtpd_peer_init(SMTPD_STATE *state);
extern void smtpd_peer_reset(SMTPD_STATE *state);
+extern int smtpd_peer_from_haproxy(SMTPD_STATE *state);
#define SMTPD_PEER_CODE_OK 2
#define SMTPD_PEER_CODE_TEMP 4
--- /dev/null
+/*++
+/* NAME
+/* smtpd_haproxy 3
+/* SUMMARY
+/* Postfix SMTP server haproxy adapter
+/* SYNOPSIS
+/* #include "smtpd.h"
+/*
+/* int smtpd_peer_from_haproxy(state)
+/* SMTPD_STATE *state;
+/* DESCRIPTION
+/* smtpd_peer_from_haproxy() receives endpoint address and
+/* port information via the haproxy protocol.
+/*
+/* The following summarizes what the Postfix SMTP server expects
+/* from an up-stream proxy adapter.
+/* .IP \(bu
+/* Validate address and port syntax. Permit only protocols
+/* that are configured with the main.cf:inet_protocols
+/* setting.
+/* .IP \(bu
+/* Convert IPv4-in-IPv6 address syntax to IPv4 syntax, when
+/* both IPv4 and IPv6 support are enabled with main.cf:inet_protocols.
+/* .IP \(bu
+/* Update the following session context fields: addr, port,
+/* rfc_addr, addr_family, dest_addr. The addr_family field
+/* applies to the client address.
+/* .IP \(bu
+/* Dynamically allocate storage for string information with
+/* mystrdup(). In case of error, leave unassigned string fields
+/* at their initial zero value.
+/* .IP \(bu
+/* Log warnings in case of data format error.
+/* .PP
+/* Arguments:
+/* .IP state
+/* Session context.
+/* DIAGNOSTICS
+/* Warnings: I/O errors, malformed haproxy line.
+/*
+/* The result value is 0 in case of success, -1 in case of
+/* error.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <sys/socket.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <myaddrinfo.h>
+#include <mymalloc.h>
+#include <stringops.h>
+
+/* Global library. */
+
+#include <smtp_stream.h>
+#include <mail_params.h>
+#include <valid_mailhost_addr.h>
+#include <haproxy_srvr.h>
+
+/* Application-specific. */
+
+#include <smtpd.h>
+
+/* SLMs. */
+
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+
+/* smtpd_peer_from_haproxy - initialize peer information from haproxy */
+
+int smtpd_peer_from_haproxy(SMTPD_STATE *state)
+{
+ const char *myname = "smtpd_peer_from_haproxy";
+ MAI_HOSTADDR_STR smtp_client_addr;
+ MAI_SERVPORT_STR smtp_client_port;
+ MAI_HOSTADDR_STR smtp_server_addr;
+ MAI_SERVPORT_STR smtp_server_port;
+ const char *proxy_err;
+ int io_err;
+ VSTRING *escape_buf;
+
+ /*
+ * Note: the haproxy_srvr_parse() routine performs address protocol
+ * checks, address and port syntax checks, and converts IPv4-in-IPv6
+ * address string syntax (:ffff::1.2.3.4) to IPv4 syntax where permitted
+ * by the main.cf:inet_protocols setting, but logs no warnings.
+ */
+#define ENABLE_DEADLINE 1
+
+ smtp_stream_setup(state->client, var_smtpd_uproxy_tmout, ENABLE_DEADLINE);
+ switch (io_err = vstream_setjmp(state->client)) {
+ default:
+ msg_panic("%s: unhandled I/O error %d", myname, io_err);
+ case SMTP_ERR_EOF:
+ msg_warn("haproxy read: unexpected EOF");
+ return (-1);
+ case SMTP_ERR_TIME:
+ msg_warn("haproxy read: timeout error");
+ return (-1);
+ case 0:
+ if (smtp_get(state->buffer, state->client, HAPROXY_MAX_LEN,
+ SMTP_GET_FLAG_NONE) != '\n') {
+ msg_warn("haproxy line > %d characters", HAPROXY_MAX_LEN);
+ return (-1);
+ }
+ if ((proxy_err = haproxy_srvr_parse(STR(state->buffer),
+ &smtp_client_addr, &smtp_client_port,
+ &smtp_server_addr, &smtp_server_port)) != 0) {
+ escape_buf = vstring_alloc(HAPROXY_MAX_LEN + 2);
+ escape(escape_buf, STR(state->buffer), LEN(state->buffer));
+ msg_warn("haproxy read: %s: %s", proxy_err, STR(escape_buf));
+ vstring_free(escape_buf);
+ return (-1);
+ }
+ state->addr = mystrdup(smtp_client_addr.buf);
+ if (strrchr(state->addr, ':') != 0) {
+ state->rfc_addr = concatenate(IPV6_COL, state->addr, (char *) 0);
+ state->addr_family = AF_INET6;
+ } else {
+ state->rfc_addr = mystrdup(state->addr);
+ state->addr_family = AF_INET;
+ }
+ state->port = mystrdup(smtp_client_port.buf);
+
+ /*
+ * Avoid surprises in the Dovecot authentication server.
+ */
+ state->dest_addr = mystrdup(smtp_server_addr.buf);
+ return (0);
+ }
+}
/* Where information is unavailable, the name and/or address
/* are set to "unknown".
/*
+/* Alternatively, the peer address and port may be obtained
+/* from a proxy server.
+/*
/* This module uses the local name service via getaddrinfo()
/* and getnameinfo(). It does not query the DNS directly.
/*
/* .IP rfc_addr
/* String of the form "ipv4addr" or "ipv6:ipv6addr" for use
/* in Received: message headers.
+/* .IP dest_addr
+/* Server address, used by the Dovecot authentication server.
/* .IP name_status
/* The name_status result field specifies how the name
/* information should be interpreted:
#include <errno.h>
#include <netdb.h>
#include <string.h>
+#include <htable.h>
/* Utility library. */
#include <mail_proto.h>
#include <valid_mailhost_addr.h>
#include <mail_params.h>
+#include <haproxy_srvr.h>
/* Application-specific. */
#include "smtpd.h"
-/* smtpd_peer_init - initialize peer information */
-
-void smtpd_peer_init(SMTPD_STATE *state)
+static INET_PROTO_INFO *proto_info;
+
+ /*
+ * XXX If we make local endpoint (getsockname) information available to
+ * Milter applications as {if_name} and {if_addr}, then we also must be able
+ * to provide this via the XCLIENT command for Milter testing.
+ *
+ * XXX If we make local port information available to policy servers or Milter
+ * applications, then we must also make this testable with the XCLIENT
+ * command, otherwise there will be confusion.
+ *
+ * XXX If we make local port information available via logging, then we must
+ * also support these attributes with the XFORWARD command.
+ *
+ * XXX If support were to be added for Milter applications in down-stream MTAs,
+ * then consistency demands that we propagate a lot of Sendmail macro
+ * information via the XFORWARD command. Otherwise we could end up with a
+ * very confusing situation.
+ */
+
+/* smtpd_peer_sockaddr_to_hostaddr - client address/port to printable form */
+
+static int smtpd_peer_sockaddr_to_hostaddr(SMTPD_STATE *state)
{
- const char *myname = "smtpd_peer_init";
- SOCKADDR_SIZE sa_length;
- struct sockaddr *sa;
- INET_PROTO_INFO *proto_info = inet_proto_info();
-
- sa = (struct sockaddr *) & (state->sockaddr);
- sa_length = sizeof(state->sockaddr);
-
- /*
- * Look up the peer address information.
- *
- * XXX If we make local endpoint (getsockname) information available to
- * Milter applications as {if_name} and {if_addr}, then we also must be
- * able to provide this via the XCLIENT command for Milter testing.
- *
- * XXX If we make local or remote port information available to policy
- * servers or Milter applications, then we must also make this testable
- * with the XCLIENT command, otherwise there will be confusion.
- *
- * XXX If we make local or remote port information available via logging,
- * then we must also support these attributes with the XFORWARD command.
- *
- * XXX If support were to be added for Milter applications in down-stream
- * MTAs, then consistency demands that we propagate a lot of Sendmail
- * macro information via the XFORWARD command. Otherwise we could end up
- * with a very confusing situation.
- */
- if (getpeername(vstream_fileno(state->client), sa, &sa_length) >= 0) {
- errno = 0;
- }
-
- /*
- * If peer went away, give up.
- */
- if (errno != 0 && errno != ENOTSOCK) {
- state->name = mystrdup(CLIENT_NAME_UNKNOWN);
- state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
- state->addr = mystrdup(CLIENT_ADDR_UNKNOWN);
- state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
- state->addr_family = AF_UNSPEC;
- state->name_status = SMTPD_PEER_CODE_PERM;
- state->reverse_name_status = SMTPD_PEER_CODE_PERM;
- state->port = mystrdup(CLIENT_PORT_UNKNOWN);
- }
+ const char *myname = "smtpd_peer_sockaddr_to_hostaddr";
+ struct sockaddr *sa = (struct sockaddr *) & (state->sockaddr);
+ SOCKADDR_SIZE sa_length = state->sockaddr_len;
/*
- * Convert the client address to printable address and hostname.
- *
- * XXX If we're given an IPv6 (or IPv4) connection from, e.g., inetd, while
- * Postfix IPv6 (or IPv4) support is turned off, don't (skip to the final
- * else clause, pretend the origin is localhost[127.0.0.1], and become an
- * open relay).
+ * XXX If we're given an IPv6 (or IPv4) connection from, e.g., inetd,
+ * while Postfix IPv6 (or IPv4) support is turned off, don't (skip to the
+ * final else clause, pretend the origin is localhost[127.0.0.1], and
+ * become an open relay).
*/
- else if (errno == 0
- && (sa->sa_family == AF_INET
+ if (sa->sa_family == AF_INET
#ifdef AF_INET6
- || sa->sa_family == AF_INET6
+ || sa->sa_family == AF_INET6
#endif
- )) {
- MAI_HOSTNAME_STR client_name;
+ ) {
MAI_HOSTADDR_STR client_addr;
MAI_SERVPORT_STR client_port;
int aierr;
state->rfc_addr = mystrdup(client_addr.buf);
state->addr_family = sa->sa_family;
}
+ return (0);
+ }
- /*
- * Look up and sanity check the client hostname.
- *
- * It is unsafe to allow numeric hostnames, especially because there
- * exists pressure to turn off the name->addr double check. In that
- * case an attacker could trivally bypass access restrictions.
- *
- * sockaddr_to_hostname() already rejects malformed or numeric names.
- */
+ /*
+ * It's not Internet.
+ */
+ else {
+ return (-1);
+ }
+}
+
+/* smtpd_peer_sockaddr_to_hostname - client hostname lookup */
+
+static void smtpd_peer_sockaddr_to_hostname(SMTPD_STATE *state)
+{
+ struct sockaddr *sa = (struct sockaddr *) & (state->sockaddr);
+ SOCKADDR_SIZE sa_length = state->sockaddr_len;
+ MAI_HOSTNAME_STR client_name;
+ int aierr;
+
+ /*
+ * Look up and sanity check the client hostname.
+ *
+ * It is unsafe to allow numeric hostnames, especially because there exists
+ * pressure to turn off the name->addr double check. In that case an
+ * attacker could trivally bypass access restrictions.
+ *
+ * sockaddr_to_hostname() already rejects malformed or numeric names.
+ */
#define TEMP_AI_ERROR(e) \
((e) == EAI_AGAIN || (e) == EAI_MEMORY || (e) == EAI_SYSTEM)
state->name_status = code; \
}
- if (var_smtpd_peername_lookup == 0) {
- state->name = mystrdup(CLIENT_NAME_UNKNOWN);
- state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
- state->name_status = SMTPD_PEER_CODE_PERM;
- state->reverse_name_status = SMTPD_PEER_CODE_PERM;
- } else if ((aierr = sockaddr_to_hostname(sa, sa_length, &client_name,
+ if (var_smtpd_peername_lookup == 0) {
+ state->name = mystrdup(CLIENT_NAME_UNKNOWN);
+ state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
+ state->name_status = SMTPD_PEER_CODE_PERM;
+ state->reverse_name_status = SMTPD_PEER_CODE_PERM;
+ } else if ((aierr = sockaddr_to_hostname(sa, sa_length, &client_name,
(MAI_SERVNAME_STR *) 0, 0)) != 0) {
- state->name = mystrdup(CLIENT_NAME_UNKNOWN);
- state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
- state->name_status = (TEMP_AI_ERROR(aierr) ?
- SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM);
- state->reverse_name_status = (TEMP_AI_ERROR(aierr) ?
+ state->name = mystrdup(CLIENT_NAME_UNKNOWN);
+ state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
+ state->name_status = (TEMP_AI_ERROR(aierr) ?
+ SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM);
+ state->reverse_name_status = (TEMP_AI_ERROR(aierr) ?
SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM);
- } else {
- struct addrinfo *res0;
- struct addrinfo *res;
+ } else {
+ struct addrinfo *res0;
+ struct addrinfo *res;
- state->name = mystrdup(client_name.buf);
- state->reverse_name = mystrdup(client_name.buf);
- state->name_status = SMTPD_PEER_CODE_OK;
- state->reverse_name_status = SMTPD_PEER_CODE_OK;
+ state->name = mystrdup(client_name.buf);
+ state->reverse_name = mystrdup(client_name.buf);
+ state->name_status = SMTPD_PEER_CODE_OK;
+ state->reverse_name_status = SMTPD_PEER_CODE_OK;
- /*
- * Reject the hostname if it does not list the peer address.
- * Without further validation or qualification, such information
- * must not be allowed to enter the audit trail, as people would
- * draw false conclusions.
- */
- aierr = hostname_to_sockaddr_pf(state->name, state->addr_family,
- (char *) 0, 0, &res0);
- if (aierr) {
- msg_warn("hostname %s does not resolve to address %s: %s",
- state->name, state->addr, MAI_STRERROR(aierr));
- REJECT_PEER_NAME(state, (TEMP_AI_ERROR(aierr) ?
+ /*
+ * Reject the hostname if it does not list the peer address. Without
+ * further validation or qualification, such information must not be
+ * allowed to enter the audit trail, as people would draw false
+ * conclusions.
+ */
+ aierr = hostname_to_sockaddr_pf(state->name, state->addr_family,
+ (char *) 0, 0, &res0);
+ if (aierr) {
+ msg_warn("hostname %s does not resolve to address %s: %s",
+ state->name, state->addr, MAI_STRERROR(aierr));
+ REJECT_PEER_NAME(state, (TEMP_AI_ERROR(aierr) ?
SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_FORGED));
- } else {
- for (res = res0; /* void */ ; res = res->ai_next) {
- if (res == 0) {
- msg_warn("hostname %s does not resolve to address %s",
- state->name, state->addr);
- REJECT_PEER_NAME(state, SMTPD_PEER_CODE_FORGED);
- break;
- }
- if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
- msg_info("skipping address family %d for host %s",
- res->ai_family, state->name);
- continue;
- }
- if (sock_addr_cmp_addr(res->ai_addr, sa) == 0)
- break; /* keep peer name */
+ } else {
+ for (res = res0; /* void */ ; res = res->ai_next) {
+ if (res == 0) {
+ msg_warn("hostname %s does not resolve to address %s",
+ state->name, state->addr);
+ REJECT_PEER_NAME(state, SMTPD_PEER_CODE_FORGED);
+ break;
+ }
+ if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
+ msg_info("skipping address family %d for host %s",
+ res->ai_family, state->name);
+ continue;
}
- freeaddrinfo(res0);
+ if (sock_addr_cmp_addr(res->ai_addr, sa) == 0)
+ break; /* keep peer name */
}
+ freeaddrinfo(res0);
}
}
+}
+
+/* smtpd_peer_hostaddr_to_sockaddr - convert numeric string to binary */
+
+static void smtpd_peer_hostaddr_to_sockaddr(SMTPD_STATE *state)
+{
+ const char *myname = "smtpd_peer_hostaddr_to_sockaddr";
+ struct addrinfo *res;
+ int aierr;
+
+ if ((aierr = hostaddr_to_sockaddr(state->addr, state->port,
+ SOCK_STREAM, &res)) != 0)
+ msg_fatal("%s: cannot convert client address/port to string: %s",
+ myname, MAI_STRERROR(aierr));
+ if (res->ai_addrlen > sizeof(state->sockaddr))
+ msg_panic("%s: address length > struct sockaddr_storage", myname);
+ memcpy((char *) &(state->sockaddr), res->ai_addr, res->ai_addrlen);
+ state->sockaddr_len = res->ai_addrlen;
+ freeaddrinfo(res);
+}
+
+/* smtpd_peer_not_inet - non-socket or non-Internet endpoint */
+
+static void smtpd_peer_not_inet(SMTPD_STATE *state)
+{
/*
* If it's not Internet, assume the client is local, and avoid using the
* naming service because that can hang when the machine is disconnected.
*/
- else {
- state->name = mystrdup("localhost");
- state->reverse_name = mystrdup("localhost");
- if (proto_info->sa_family_list[0] == PF_INET6) {
- state->addr = mystrdup("::1"); /* XXX bogus. */
- state->rfc_addr = mystrdup(IPV6_COL "::1"); /* XXX bogus. */
- } else {
- state->addr = mystrdup("127.0.0.1");/* XXX bogus. */
- state->rfc_addr = mystrdup("127.0.0.1"); /* XXX bogus. */
- }
- state->addr_family = AF_UNSPEC;
- state->name_status = SMTPD_PEER_CODE_OK;
- state->reverse_name_status = SMTPD_PEER_CODE_OK;
- state->port = mystrdup("0"); /* XXX bogus. */
+ state->name = mystrdup("localhost");
+ state->reverse_name = mystrdup("localhost");
+#ifdef AF_INET6
+ if (proto_info->sa_family_list[0] == PF_INET6) {
+ state->addr = mystrdup("::1"); /* XXX bogus. */
+ state->rfc_addr = mystrdup(IPV6_COL "::1"); /* XXX bogus. */
+ } else
+#endif
+ {
+ state->addr = mystrdup("127.0.0.1"); /* XXX bogus. */
+ state->rfc_addr = mystrdup("127.0.0.1");/* XXX bogus. */
+ }
+ state->addr_family = AF_UNSPEC;
+ state->name_status = SMTPD_PEER_CODE_OK;
+ state->reverse_name_status = SMTPD_PEER_CODE_OK;
+ state->port = mystrdup("0"); /* XXX bogus. */
+}
+
+/* smtpd_peer_no_client - peer went away, or peer info unavailable */
+
+static void smtpd_peer_no_client(SMTPD_STATE *state)
+{
+ smtpd_peer_reset(state);
+ state->name = mystrdup(CLIENT_NAME_UNKNOWN);
+ state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
+ state->addr = mystrdup(CLIENT_ADDR_UNKNOWN);
+ state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
+ state->addr_family = AF_UNSPEC;
+ state->name_status = SMTPD_PEER_CODE_PERM;
+ state->reverse_name_status = SMTPD_PEER_CODE_PERM;
+ state->port = mystrdup(CLIENT_PORT_UNKNOWN);
+}
+
+/* smtpd_peer_from_pass_attr - initialize from attribute hash */
+
+static void smtpd_peer_from_pass_attr(SMTPD_STATE *state)
+{
+ HTABLE *attr = (HTABLE *) vstream_context(state->client);
+ const char *cp;
+
+ /*
+ * Extract the client endpoint information from the attribute hash.
+ */
+ if ((cp = htable_find(attr, MAIL_ATTR_ACT_CLIENT_ADDR)) == 0)
+ msg_fatal("missing client address from proxy");
+ if (strrchr(cp, ':') != 0) {
+ if (valid_ipv6_hostaddr(cp, DO_GRIPE) == 0)
+ msg_fatal("bad IPv6 client address syntax from proxy: %s", cp);
+ state->addr = mystrdup(cp);
+ state->rfc_addr = concatenate(IPV6_COL, cp, (char *) 0);
+ state->addr_family = AF_INET6;
+ } else {
+ if (valid_ipv4_hostaddr(cp, DO_GRIPE) == 0)
+ msg_fatal("bad IPv4 client address syntax from proxy: %s", cp);
+ state->addr = mystrdup(cp);
+ state->rfc_addr = mystrdup(cp);
+ state->addr_family = AF_INET;
+ }
+ if ((cp = htable_find(attr, MAIL_ATTR_ACT_CLIENT_PORT)) == 0)
+ msg_fatal("missing client port from proxy");
+ if (valid_hostport(cp, DO_GRIPE) == 0)
+ msg_fatal("bad TCP client port number syntax from proxy: %s", cp);
+ state->port = mystrdup(cp);
+
+ /*
+ * Avoid surprises in the Dovecot authentication server.
+ */
+ if ((cp = htable_find(attr, MAIL_ATTR_ACT_SERVER_ADDR)) == 0)
+ msg_fatal("missing server address from proxy");
+ if (valid_hostaddr(cp, DO_GRIPE) == 0)
+ msg_fatal("bad IPv6 client address syntax from proxy: %s", cp);
+ state->dest_addr = mystrdup(cp);
+
+ /*
+ * Convert the client address from string to binary form.
+ */
+ smtpd_peer_hostaddr_to_sockaddr(state);
+}
+
+/* smtpd_peer_from_default - try to initialize peer information from socket */
+
+static void smtpd_peer_from_default(SMTPD_STATE *state)
+{
+ SOCKADDR_SIZE sa_length = sizeof(state->sockaddr);
+ struct sockaddr *sa = (struct sockaddr *) & (state->sockaddr);
+
+ /*
+ * The "no client" routine provides surrogate information so that the
+ * application can produce sensible logging when a client disconnects
+ * before the server wakes up. The "not inet" routine provides surrogate
+ * state for (presumably) local IPC channels.
+ */
+ if (getpeername(vstream_fileno(state->client), sa, &sa_length) < 0) {
+ if (errno == ENOTSOCK)
+ smtpd_peer_not_inet(state);
+ else
+ smtpd_peer_no_client(state);
+ } else {
+ state->sockaddr_len = sa_length;
+ if (smtpd_peer_sockaddr_to_hostaddr(state) < 0)
+ smtpd_peer_not_inet(state);
+ }
+}
+
+/* smtpd_peer_from_proxy - get endpoint info from proxy agent */
+
+static void smtpd_peer_from_proxy(SMTPD_STATE *state)
+{
+ typedef struct {
+ const char *name;
+ int (*endpt_lookup) (SMTPD_STATE *);
+ } SMTPD_ENDPT_LOOKUP_INFO;
+ static const SMTPD_ENDPT_LOOKUP_INFO smtpd_endpt_lookup_info[] = {
+ HAPROXY_PROTO_NAME, smtpd_peer_from_haproxy,
+ 0,
+ };
+ const SMTPD_ENDPT_LOOKUP_INFO *pp;
+
+ /*
+ * When the proxy information is unavailable, we can't maintain an audit
+ * trail or enforce access control, therefore we forcibly hang up.
+ */
+ for (pp = smtpd_endpt_lookup_info; /* see below */ ; pp++) {
+ if (pp->name == 0)
+ msg_fatal("unsupported %s value: %s",
+ VAR_SMTPD_UPROXY_PROTO, var_smtpd_uproxy_proto);
+ if (strcmp(var_smtpd_uproxy_proto, pp->name) == 0)
+ break;
}
+ if (pp->endpt_lookup(state) < 0) {
+ smtpd_peer_no_client(state);
+ state->flags |= SMTPD_FLAG_HANGUP;
+ } else {
+ smtpd_peer_hostaddr_to_sockaddr(state);
+ }
+}
+
+/* smtpd_peer_init - initialize peer information */
+
+void smtpd_peer_init(SMTPD_STATE *state)
+{
+
+ /*
+ * Initialize.
+ */
+ if (proto_info == 0)
+ proto_info = inet_proto_info();
+
+ /*
+ * Prepare for partial initialization after error.
+ */
+ memset((char *) &(state->sockaddr), 0, sizeof(state->sockaddr));
+ state->sockaddr_len = 0;
+ state->name = 0;
+ state->reverse_name = 0;
+ state->addr = 0;
+ state->namaddr = 0;
+ state->rfc_addr = 0;
+ state->port = 0;
+ state->dest_addr = 0;
+
+ /*
+ * Determine the remote SMTP client address and port.
+ *
+ * XXX In stand-alone mode, don't assume that the peer will be a local
+ * process. That could introduce a gaping hole when the SMTP daemon is
+ * hooked up to the network via inetd or some other super-server.
+ */
+ if (vstream_context(state->client) != 0) {
+ smtpd_peer_from_pass_attr(state);
+ if (*var_smtpd_uproxy_proto != 0)
+ msg_warn("ignoring non-empty %s setting behind postscreen",
+ VAR_SMTPD_UPROXY_PROTO);
+ } else if (SMTPD_STAND_ALONE(state) || *var_smtpd_uproxy_proto == 0) {
+ smtpd_peer_from_default(state);
+ } else {
+ smtpd_peer_from_proxy(state);
+ }
+
+ /*
+ * Determine the remote SMTP client hostname. Note: some of the handlers
+ * above provide surrogate endpoint information in case of error. In that
+ * case, leave the surrogate information alone.
+ */
+ if (state->name == 0)
+ smtpd_peer_sockaddr_to_hostname(state);
/*
* Do the name[addr]:port formatting for pretty reports.
void smtpd_peer_reset(SMTPD_STATE *state)
{
- myfree(state->name);
- myfree(state->reverse_name);
- myfree(state->addr);
- myfree(state->namaddr);
- myfree(state->rfc_addr);
- myfree(state->port);
+ if (state->name)
+ myfree(state->name);
+ if (state->reverse_name)
+ myfree(state->reverse_name);
+ if (state->addr)
+ myfree(state->addr);
+ if (state->namaddr)
+ myfree(state->namaddr);
+ if (state->rfc_addr)
+ myfree(state->rfc_addr);
+ if (state->port)
+ myfree(state->port);
+ if (state->dest_addr)
+ myfree(state->dest_addr);
}
if ((state->sasl_server =
XSASL_SERVER_CREATE(smtpd_sasl_impl, &create_args,
stream = state->client,
- server_addr = "", /* need smtpd_peer.c update */
+ server_addr = (state->dest_addr ?
+ state->dest_addr : ""),
client_addr = ADDR_OR_EMPTY(state->addr,
CLIENT_ADDR_UNKNOWN),
service = SMTPD_SASL_SERVICE,
vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.c \
write_buf.c write_wait.c sane_basename.c format_tv.c allspace.c \
allascii.c load_file.c killme_after.c vstream_tweak.c \
- unix_pass_listen.c unix_pass_trigger.c edit_file.c inet_windowsize.c \
+ pass_trigger.c edit_file.c inet_windowsize.c \
unix_pass_fd_fix.c dict_cache.c valid_utf_8.c dict_thash.c \
- ip_match.c nbbio.c stream_pass_connect.c base32_code.c dict_test.c \
+ ip_match.c nbbio.c base32_code.c dict_test.c \
dict_fail.c msg_rate_delay.c dict_surrogate.c warn_stat.c \
- dict_sockmap.c line_number.c
+ dict_sockmap.c line_number.c recv_pass_attr.c pass_accept.c
OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.o \
write_buf.o write_wait.o sane_basename.o format_tv.o allspace.o \
allascii.o load_file.o killme_after.o vstream_tweak.o \
- unix_pass_listen.o unix_pass_trigger.o edit_file.o inet_windowsize.o \
+ pass_trigger.o edit_file.o inet_windowsize.o \
unix_pass_fd_fix.o dict_cache.o valid_utf_8.o dict_thash.o \
- ip_match.o nbbio.o stream_pass_connect.o base32_code.o dict_test.o \
+ ip_match.o nbbio.o base32_code.o dict_test.o \
dict_fail.o msg_rate_delay.o dict_surrogate.o warn_stat.o \
- dict_sockmap.o line_number.o
+ dict_sockmap.o line_number.o recv_pass_attr.o pass_accept.o
HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \
dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \
attr_scan0 host_port attr_scan_plain attr_print_plain htable \
unix_recv_fd unix_send_fd stream_recv_fd stream_send_fd hex_code \
myaddrinfo myaddrinfo4 inet_proto sane_basename format_tv \
- valid_utf_8 ip_match base32_code msg_rate_delay netstring
+ valid_utf_8 ip_match base32_code msg_rate_delay netstring \
+ vstream
LIB_DIR = ../../lib
INC_DIR = ../../include
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
+vstream: $(LIB)
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
+ mv junk $@.o
+
tests: valid_hostname_test mac_expand_test dict_test unescape_test \
hex_quote_test ctable_test inet_addr_list_test base64_code_test \
attr_scan64_test attr_scan0_test dict_pcre_test host_port_test \
exec_command.o: msg.h
exec_command.o: sys_defs.h
fifo_listen.o: fifo_listen.c
+fifo_listen.o: htable.h
fifo_listen.o: iostuff.h
fifo_listen.o: listen.h
fifo_listen.o: msg.h
inet_connect.o: sys_defs.h
inet_connect.o: timed_connect.h
inet_listen.o: host_port.h
+inet_listen.o: htable.h
inet_listen.o: inet_listen.c
inet_listen.o: inet_proto.h
inet_listen.o: iostuff.h
open_lock.o: vbuf.h
open_lock.o: vstream.h
open_lock.o: vstring.h
+pass_accept.o: attr.h
+pass_accept.o: htable.h
+pass_accept.o: iostuff.h
+pass_accept.o: listen.h
+pass_accept.o: msg.h
+pass_accept.o: pass_accept.c
+pass_accept.o: sys_defs.h
+pass_accept.o: vbuf.h
+pass_accept.o: vstream.h
+pass_trigger.o: connect.h
+pass_trigger.o: events.h
+pass_trigger.o: iostuff.h
+pass_trigger.o: msg.h
+pass_trigger.o: mymalloc.h
+pass_trigger.o: pass_trigger.c
+pass_trigger.o: sys_defs.h
+pass_trigger.o: trigger.h
peekfd.o: iostuff.h
peekfd.o: peekfd.c
peekfd.o: sys_defs.h
readlline.o: vbuf.h
readlline.o: vstream.h
readlline.o: vstring.h
+recv_pass_attr.o: attr.h
+recv_pass_attr.o: htable.h
+recv_pass_attr.o: iostuff.h
+recv_pass_attr.o: listen.h
+recv_pass_attr.o: mymalloc.h
+recv_pass_attr.o: recv_pass_attr.c
+recv_pass_attr.o: sys_defs.h
+recv_pass_attr.o: vbuf.h
+recv_pass_attr.o: vstream.h
ring.o: ring.c
ring.o: ring.h
safe_getenv.o: safe.h
stream_connect.o: msg.h
stream_connect.o: stream_connect.c
stream_connect.o: sys_defs.h
+stream_listen.o: htable.h
stream_listen.o: iostuff.h
stream_listen.o: listen.h
stream_listen.o: msg.h
stream_listen.o: stream_listen.c
stream_listen.o: sys_defs.h
-stream_pass_connect.o: connect.h
-stream_pass_connect.o: iostuff.h
-stream_pass_connect.o: msg.h
-stream_pass_connect.o: stream_pass_connect.c
-stream_pass_connect.o: sys_defs.h
stream_recv_fd.o: iostuff.h
stream_recv_fd.o: msg.h
stream_recv_fd.o: stream_recv_fd.c
stream_send_fd.o: stream_send_fd.c
stream_send_fd.o: sys_defs.h
stream_test.o: connect.h
+stream_test.o: htable.h
stream_test.o: iostuff.h
stream_test.o: listen.h
stream_test.o: msg.h
unix_connect.o: sys_defs.h
unix_connect.o: timed_connect.h
unix_connect.o: unix_connect.c
+unix_listen.o: htable.h
unix_listen.o: iostuff.h
unix_listen.o: listen.h
unix_listen.o: msg.h
unix_pass_fd_fix.o: unix_pass_fd_fix.c
unix_pass_fd_fix.o: vbuf.h
unix_pass_fd_fix.o: vstring.h
-unix_pass_listen.o: iostuff.h
-unix_pass_listen.o: listen.h
-unix_pass_listen.o: msg.h
-unix_pass_listen.o: sane_accept.h
-unix_pass_listen.o: sys_defs.h
-unix_pass_listen.o: unix_pass_listen.c
-unix_pass_trigger.o: connect.h
-unix_pass_trigger.o: events.h
-unix_pass_trigger.o: iostuff.h
-unix_pass_trigger.o: msg.h
-unix_pass_trigger.o: mymalloc.h
-unix_pass_trigger.o: sys_defs.h
-unix_pass_trigger.o: trigger.h
-unix_pass_trigger.o: unix_pass_trigger.c
unix_recv_fd.o: iostuff.h
unix_recv_fd.o: msg.h
unix_recv_fd.o: sys_defs.h
extern int unix_connect(const char *, int, int);
extern int inet_connect(const char *, int, int);
extern int stream_connect(const char *, int, int);
-extern int stream_pass_connect(const char *, int, int);
-
-#define unix_pass_connect unix_connect
/* LICENSE
/* .ad
* Utility library.
*/
#include <iostuff.h>
+#include <htable.h>
/*
* Listener external interface.
extern int fifo_listen(const char *, int, int);
extern int stream_listen(const char *, int, int);
-#define unix_pass_listen unix_listen
-#define stream_pass_listen stream_listen
-
extern int inet_accept(int);
extern int unix_accept(int);
extern int stream_accept(int);
-extern int unix_pass_accept(int);
-#define stream_pass_accept stream_accept
+extern int recv_pass_attr(int, HTABLE **, int, ssize_t);
+extern int pass_accept(int);
+extern int pass_accept_attr(int, HTABLE **);
/* LICENSE
/* .ad
void msg_vprintf(int level, const char *format, va_list ap)
{
+ int saved_errno = errno;
+
if (msg_vprintf_lock == 0) {
msg_vprintf_lock = 1;
/* On-the-fly initialization for debugging test programs only. */
msg_text(level, vstring_str(msg_buffer));
msg_vprintf_lock = 0;
}
+ errno = saved_errno;
}
/* msg_text - sanitize and log pre-formatted text */
--- /dev/null
+/*++
+/* NAME
+/* pass_accept 3
+/* SUMMARY
+/* start UNIX-domain file descriptor listener
+/* SYNOPSIS
+/* #include <listen.h>
+/*
+/* int pass_accept(listen_fd)
+/* int listen_fd;
+/*
+/* int pass_accept_attr(listen_fd, attr)
+/* int listen_fd;
+/* HTABLE **attr;
+/* DESCRIPTION
+/* This module implements a listener that receives one attribute list
+/* and file descriptor over each a local connection that is made to it.
+/*
+/* Arguments:
+/* .IP attr
+/* Pointer to attribute list pointer. In case of error, or
+/* no attributes, the attribute list pointer is set to null.
+/* .IP listen_fd
+/* File descriptor returned by LOCAL_LISTEN().
+/* DIAGNOSTICS
+/* Warnings: I/O errors, timeout.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <errno.h>
+#include <unistd.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <listen.h>
+#include <attr.h>
+
+#define PASS_ACCEPT_TMOUT 100
+
+/* pass_accept - accept descriptor */
+
+int pass_accept(int listen_fd)
+{
+ const char *myname = "pass_accept";
+ int accept_fd;
+ int recv_fd = -1;
+
+ accept_fd = LOCAL_ACCEPT(listen_fd);
+ if (accept_fd < 0) {
+ if (errno != EAGAIN)
+ msg_warn("%s: cannot accept connection: %m", myname);
+ return (-1);
+ } else {
+ if (read_wait(accept_fd, PASS_ACCEPT_TMOUT) < 0)
+ msg_warn("%s: timeout receiving file descriptor: %m", myname);
+ else if ((recv_fd = LOCAL_RECV_FD(accept_fd)) < 0)
+ msg_warn("%s: cannot receive file descriptor: %m", myname);
+ if (close(accept_fd) < 0)
+ msg_warn("%s: close: %m", myname);
+ return (recv_fd);
+ }
+}
+
+/* pass_accept_attr - accept attribute list and descriptor */
+
+int pass_accept_attr(int listen_fd, HTABLE **attr)
+{
+ const char *myname = "pass_accept_attr";
+ int accept_fd;
+ int recv_fd = -1;
+
+ *attr = 0;
+ accept_fd = LOCAL_ACCEPT(listen_fd);
+ if (accept_fd < 0) {
+ if (errno != EAGAIN)
+ msg_warn("%s: cannot accept connection: %m", myname);
+ return (-1);
+ } else {
+ if (read_wait(accept_fd, PASS_ACCEPT_TMOUT) < 0)
+ msg_warn("%s: timeout receiving file descriptor: %m", myname);
+ else if ((recv_fd = LOCAL_RECV_FD(accept_fd)) < 0)
+ msg_warn("%s: cannot receive file descriptor: %m", myname);
+ else if (read_wait(accept_fd, PASS_ACCEPT_TMOUT) < 0
+ || recv_pass_attr(accept_fd, attr, PASS_ACCEPT_TMOUT, 0) < 0) {
+ msg_warn("%s: cannot receive connection attributes: %m", myname);
+ if (close(recv_fd) < 0)
+ msg_warn("%s: close: %m", myname);
+ recv_fd = -1;
+ }
+ if (close(accept_fd) < 0)
+ msg_warn("%s: close: %m", myname);
+ return (recv_fd);
+ }
+}
/*++
/* NAME
-/* unix_pass_trigger 3
+/* pass_trigger 3
/* SUMMARY
-/* wakeup UNIX-domain file descriptor listener
+/* trigger file descriptor listener
/* SYNOPSIS
/* #include <trigger.h>
/*
-/* int unix_pass_trigger(service, buf, len, timeout)
+/* int pass_trigger(service, buf, len, timeout)
/* const char *service;
/* const char *buf;
/* ssize_t len;
/* int timeout;
/* DESCRIPTION
-/* unix_pass_trigger() wakes up the named UNIX-domain server by sending
-/* a brief connection to it and writing the named buffer.
+/* pass_trigger() connects to the named local server by sending
+/* a file descriptor to it and writing the named buffer.
/*
/* The connection is closed by a background thread. Some kernels
/* cannot handle client-side disconnect before the server has
/* DIAGNOSTICS
/* The result is zero in case of success, -1 in case of problems.
/* SEE ALSO
-/* unix_pass_connect(3), UNIX-domain client
+/* unix_connect(3), local client
+/* stream_connect(3), streams-based client
/* LICENSE
/* .ad
/* .fi
#include <events.h>
#include <trigger.h>
-struct unix_pass_trigger {
- int fd;
+struct pass_trigger {
+ int connect_fd;
char *service;
- int *pair;
+ int pass_fd[2];
};
-/* unix_pass_trigger_event - disconnect from peer */
+/* pass_trigger_event - disconnect from peer */
-static void unix_pass_trigger_event(int event, char *context)
+static void pass_trigger_event(int event, char *context)
{
- struct unix_pass_trigger *up = (struct unix_pass_trigger *) context;
- static const char *myname = "unix_pass_trigger_event";
+ struct pass_trigger *pp = (struct pass_trigger *) context;
+ static const char *myname = "pass_trigger_event";
/*
* Disconnect.
*/
if (event == EVENT_TIME)
- msg_warn("%s: read timeout for service %s", myname, up->service);
- event_disable_readwrite(up->fd);
- event_cancel_timer(unix_pass_trigger_event, context);
+ msg_warn("%s: read timeout for service %s", myname, pp->service);
+ event_disable_readwrite(pp->connect_fd);
+ event_cancel_timer(pass_trigger_event, context);
/* Don't combine multiple close() calls into one boolean expression. */
- if (close(up->fd) < 0)
- msg_warn("%s: close %s: %m", myname, up->service);
- if (close(up->pair[0]) < 0)
+ if (close(pp->connect_fd) < 0)
+ msg_warn("%s: close %s: %m", myname, pp->service);
+ if (close(pp->pass_fd[0]) < 0)
msg_warn("%s: close pipe: %m", myname);
- if (close(up->pair[1]) < 0)
+ if (close(pp->pass_fd[1]) < 0)
msg_warn("%s: close pipe: %m", myname);
- myfree(up->service);
- myfree((char *) up);
+ myfree(pp->service);
+ myfree((char *) pp);
}
-/* unix_pass_trigger - wakeup UNIX-domain server */
+/* pass_trigger - wakeup local server */
-int unix_pass_trigger(const char *service, const char *buf, ssize_t len, int timeout)
+int pass_trigger(const char *service, const char *buf, ssize_t len, int timeout)
{
- const char *myname = "unix_pass_trigger";
- int pair[2];
- struct unix_pass_trigger *up;
- int fd;
+ const char *myname = "pass_trigger";
+ int pass_fd[2];
+ struct pass_trigger *pp;
+ int connect_fd;
if (msg_verbose > 1)
msg_info("%s: service %s", myname, service);
/*
* Connect...
*/
- if ((fd = unix_pass_connect(service, BLOCKING, timeout)) < 0) {
+ if ((connect_fd = LOCAL_CONNECT(service, BLOCKING, timeout)) < 0) {
if (msg_verbose)
msg_warn("%s: connect to %s: %m", myname, service);
return (-1);
}
- close_on_exec(fd, CLOSE_ON_EXEC);
+ close_on_exec(connect_fd, CLOSE_ON_EXEC);
/*
* Create a pipe, and send one pipe end to the server.
*/
- if (pipe(pair) < 0)
+ if (pipe(pass_fd) < 0)
msg_fatal("%s: pipe: %m", myname);
- close_on_exec(pair[0], CLOSE_ON_EXEC);
- close_on_exec(pair[1], CLOSE_ON_EXEC);
- if (unix_send_fd(fd, pair[0]) < 0)
+ close_on_exec(pass_fd[0], CLOSE_ON_EXEC);
+ close_on_exec(pass_fd[1], CLOSE_ON_EXEC);
+ if (LOCAL_SEND_FD(connect_fd, pass_fd[0]) < 0)
msg_fatal("%s: send file descriptor: %m", myname);
/*
* Stash away context.
*/
- up = (struct unix_pass_trigger *) mymalloc(sizeof(*up));
- up->fd = fd;
- up->service = mystrdup(service);
- up->pair = pair;
+ pp = (struct pass_trigger *) mymalloc(sizeof(*pp));
+ pp->connect_fd = connect_fd;
+ pp->service = mystrdup(service);
+ pp->pass_fd[0] = pass_fd[0];
+ pp->pass_fd[1] = pass_fd[1];
/*
* Write the request...
*/
- if (write_buf(pair[1], buf, len, timeout) < 0
- || write_buf(pair[1], "", 1, timeout) < 0)
+ if (write_buf(pass_fd[1], buf, len, timeout) < 0
+ || write_buf(pass_fd[1], "", 1, timeout) < 0)
if (msg_verbose)
msg_warn("%s: write to %s: %m", myname, service);
* Wakeup when the peer disconnects, or when we lose patience.
*/
if (timeout > 0)
- event_request_timer(unix_pass_trigger_event, (char *) up, timeout + 100);
- event_enable_read(fd, unix_pass_trigger_event, (char *) up);
+ event_request_timer(pass_trigger_event, (char *) pp, timeout + 100);
+ event_enable_read(connect_fd, pass_trigger_event, (char *) pp);
return (0);
}
--- /dev/null
+/*++
+/* NAME
+/* recv_pass_attr 3
+/* SUMMARY
+/* predicate if string is all numerical
+/* SYNOPSIS
+/* #include <listen.h>
+/*
+/* int recv_pass_attr(fd, attr, timeout, bufsize)
+/* int fd;
+/* HTABLE **attr;
+/* int timeout;
+/* ssize_t bufsize;
+/* DESCRIPTION
+/* recv_pass_attr() receives named attributes over the specified
+/* The result value is zero for success, -1 for error.
+/*
+/* Arguments:
+/* .IP fd
+/* The file descriptor to read from.
+/* .IP attr
+/* Pointer to attribute list pointer. The target is set to
+/* zero on error or when the received attribute list is empty,
+/* ohterwise it is assigned a pointer to non-empty attribute
+/* list.
+/* .IP timeout
+/* The deadline for receiving all attributes.
+/* .IP bufsize
+/* The read buffer size. Specify 1 to avoid reading past the
+/* end of the attribute list.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <iostuff.h>
+#include <htable.h>
+#include <vstream.h>
+#include <attr.h>
+#include <mymalloc.h>
+#include <listen.h>
+
+/* recv_pass_attr - receive connection attributes */
+
+int recv_pass_attr(int fd, HTABLE **attr, int timeout, ssize_t bufsize)
+{
+ VSTREAM *fp;
+ int stream_err;
+
+ /*
+ * Set up a temporary VSTREAM to receive the attributes.
+ *
+ * XXX We use one-character reads to simplify the implementation.
+ */
+ fp = vstream_fdopen(fd, O_RDWR);
+ vstream_control(fp,
+ VSTREAM_CTL_BUFSIZE, bufsize,
+ VSTREAM_CTL_TIMEOUT, timeout,
+ VSTREAM_CTL_START_DEADLINE,
+ VSTREAM_CTL_END);
+ (void) attr_scan(fp, ATTR_FLAG_NONE,
+ ATTR_TYPE_HASH, *attr = htable_create(1),
+ ATTR_TYPE_END);
+ stream_err = (vstream_feof(fp) || vstream_ferror(fp));
+ vstream_fdclose(fp);
+
+ /*
+ * Error reporting and recovery.
+ */
+ if (stream_err) {
+ htable_free(*attr, myfree);
+ *attr = 0;
+ return (-1);
+ } else {
+ if ((*attr)->used == 0) {
+ htable_free(*attr, myfree);
+ *attr = 0;
+ }
+ return (0);
+ }
+}
return (-1);
return (fdinfo.fd);
#else
- msg_fatal("stream connections are not implemented");
+ msg_fatal("stream connections are not implemented");
#endif
}
+++ /dev/null
-/*++
-/* NAME
-/* stream_pass_connect 3
-/* SUMMARY
-/* connect to stream-based descriptor listener
-/* SYNOPSIS
-/* #include <connect.h>
-/*
-/* int stream_pass_connect(path, block_mode, timeout)
-/* const char *path;
-/* int block_mode;
-/* int timeout;
-/* DESCRIPTION
-/* stream_pass_connect() connects to a stream-based descriptor
-/* listener for the specified pathname, and returns the resulting
-/* file descriptor. The next operation is to stream_send_fd()
-/* a file descriptor and then close() the connection once the
-/* server has received the file descriptor.
-/*
-/* Arguments:
-/* .IP path
-/* Null-terminated string with listener endpoint name.
-/* .IP block_mode
-/* Either NON_BLOCKING for a non-blocking stream, or BLOCKING for
-/* blocking mode. However, a stream connection succeeds or fails
-/* immediately.
-/* .IP timeout
-/* This argument is ignored; it is present for compatibility with
-/* other interfaces. Stream connections succeed or fail immediately.
-/* DIAGNOSTICS
-/* The result is -1 in case the connection could not be made.
-/* Fatal errors: other system call failures.
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-
-#ifdef STREAM_CONNECTIONS
-
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#endif
-
-/* Utility library. */
-
-#include <msg.h>
-#include <connect.h>
-
-/* stream_pass_connect - connect to stream-based descriptor listener */
-
-int stream_pass_connect(const char *path, int block_mode, int unused_timeout)
-{
-#ifdef STREAM_CONNECTIONS
- const char *myname = "stream_pass_connect";
- int fifo;
-
- /*
- * The requested file system object must exist, otherwise we can't reach
- * the server.
- */
- if ((fifo = open(path, O_WRONLY | O_NONBLOCK, 0)) < 0)
- return (-1);
-
- /*
- * This is for {unix,inet}_connect() compatibility.
- */
- non_blocking(fifo, block_mode);
-
- return (fifo);
-#else
- msg_fatal("stream connections are not implemented");
-#endif
-}
#define LOCAL_TRIGGER stream_trigger
#define LOCAL_SEND_FD stream_send_fd
#define LOCAL_RECV_FD stream_recv_fd
-#define PASS_CONNECT stream_pass_connect
-#define PASS_LISTEN stream_pass_listen
-#define PASS_ACCEPT stream_pass_accept
-#define PASS_TRIGGER stream_pass_trigger
#define HAS_VOLATILE_LOCKS
#define BROKEN_READ_SELECT_ON_TCP_SOCKET
#define CANT_WRITE_BEFORE_SENDING_FD
#define LOCAL_RECV_FD unix_recv_fd
#endif
-#ifndef PASS_LISTEN
-#define PASS_CONNECT unix_pass_connect
-#define PASS_LISTEN unix_pass_listen
-#define PASS_ACCEPT unix_pass_accept
-#define PASS_TRIGGER unix_pass_trigger
-#endif
-
#if !defined (HAVE_SYS_NDIR_H) && !defined (HAVE_SYS_DIR_H) \
&& !defined (HAVE_NDIR_H)
#define HAVE_DIRENT_H
extern int inet_trigger(const char *, const char *, ssize_t, int);
extern int fifo_trigger(const char *, const char *, ssize_t, int);
extern int stream_trigger(const char *, const char *, ssize_t, int);
-extern int unix_pass_trigger(const char *, const char *, ssize_t, int);
-
-#define stream_pass_trigger stream_trigger
+extern int pass_trigger(const char *, const char *, ssize_t, int);
/* LICENSE
/* .ad
+++ /dev/null
-/*++
-/* NAME
-/* unix_pass_listen 3
-/* SUMMARY
-/* start UNIX-domain file descriptor listener
-/* SYNOPSIS
-/* #include <listen.h>
-/*
-/* int unix_pass_listen(path, backlog, block_mode)
-/* const char *path;
-/* int backlog;
-/* int block_mode;
-/*
-/* int unix_pass_accept(fd)
-/* int fd;
-/* DESCRIPTION
-/* This module implements a listener that receives one file descriptor
-/* across each UNIX-domain connection that is made to it.
-/*
-/* unix_pass_listen() creates a listener endpoint with the specified
-/* permissions, and returns a file descriptor to be used for accepting
-/* descriptors.
-/*
-/* unix_pass_accept() accepts a descriptor.
-/*
-/* Arguments:
-/* .IP path
-/* Null-terminated string with connection destination.
-/* .IP backlog
-/* This argument exists for compatibility and is ignored.
-/* .IP block_mode
-/* Either NON_BLOCKING or BLOCKING. This does not affect the
-/* mode of accepted connections.
-/* .IP fd
-/* File descriptor returned by unix_pass_listen().
-/* DIAGNOSTICS
-/* Fatal errors: unix_pass_listen() aborts upon any system call failure.
-/* unix_pass_accept() leaves all error handling up to the caller.
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <sys/socket.h>
-#include <errno.h>
-#include <unistd.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <sane_accept.h>
-#include <listen.h>
-
-/* unix_pass_accept - accept descriptor */
-
-int unix_pass_accept(int listen_fd)
-{
- const char *myname = "unix_pass_accept";
- int accept_fd;
- int recv_fd = -1;
-
- accept_fd = sane_accept(listen_fd, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0);
- if (accept_fd < 0) {
- if (errno != EAGAIN)
- msg_warn("%s: accept connection: %m", myname);
- return (-1);
- } else {
- if (read_wait(accept_fd, 100) < 0)
- msg_warn("%s: timeout receiving file descriptor: %m", myname);
- else if ((recv_fd = unix_recv_fd(accept_fd)) < 0)
- msg_warn("%s: cannot receive file descriptor: %m", myname);
- if (close(accept_fd) < 0)
- msg_warn("%s: close: %m", myname);
- return (recv_fd);
- }
-}
/* int valid_ipv6_hostaddr(addr, gripe)
/* const char *addr;
/* int gripe;
+/*
+/* int valid_hostport(port, gripe)
+/* const char *port;
+/* int gripe;
/* DESCRIPTION
/* valid_hostname() scrutinizes a hostname: the name should
/* be no longer than VALID_HOSTNAME_LEN characters, should
/* These routines operate silently unless the gripe parameter
/* specifies a non-zero value. The macros DO_GRIPE and DONT_GRIPE
/* provide suitable constants.
+/*
+/* valid_hostport() requires that the input is a valid string
+/* representation of a TCP or UDP port number.
/* BUGS
/* valid_hostmumble() does not guarantee that string lengths
/* fit the buffer sizes defined in myaddrinfo(3h).
#include <sys_defs.h>
#include <string.h>
#include <ctype.h>
+#include <stdlib.h>
/* Utility library. */
}
}
+/* valid_hostport - validate numeric port */
+
+int valid_hostport(const char *str, int gripe)
+{
+ const char *myname = "valid_hostport";
+ int port;
+
+ if (str[0] == '0' && str[1] != 0) {
+ if (gripe)
+ msg_warn("%s: leading zero in port number: %.100s", myname, str);
+ return (0);
+ }
+ if (alldig(str) == 0) {
+ if (gripe)
+ msg_warn("%s: non-numeric port number: %.100s", myname, str);
+ return (0);
+ }
+ if (strlen(str) > strlen("65535")
+ || (port = atoi(str)) > 65535 || port < 0) {
+ if (gripe)
+ msg_warn("%s: out-of-range port number: %.100s", myname, str);
+ return (0);
+ }
+ return (1);
+}
+
#ifdef TEST
/*
extern int valid_hostaddr(const char *, int);
extern int valid_ipv4_hostaddr(const char *, int);
extern int valid_ipv6_hostaddr(const char *, int);
+extern int valid_hostport(const char *, int);
/* LICENSE
/* .ad
/* This involves allocation of additional memory that normally isn't
/* used.
/* .IP "VSTREAM_CTL_BUFSIZE (ssize_t)"
-/* Specify a non-default write buffer size, or zero to implement
-/* a no-op. Requests to shrink an existing buffer size are
-/* ignored. Requests to change a fixed-size buffer (stdin,
-/* stdout, stderr) are not allowed.
+/* Specify a non-default buffer size, or zero to implement
+/* a no-op. Requests to resize a fixed-size buffer (stderr)
+/* are not allowed.
/*
/* NOTE: the VSTREAM_CTL_BUFSIZE request specifies intent, not
/* reality. Actual buffer sizes are not updated immediately.
-/* Instead, an existing write buffer will be resized when it
-/* is full, and an existing read buffer will be resized when
-/* the buffer is filled.
+/* Instead, a write buffer size will be updated when writing
+/* to a stream for the first time, or when writing to a full
+/* buffer, and a read buffer size will be updated when reading
+/* from a stream for the first time, or when reading from an
+/* empty buffer.
+/*
+/* NOTE: the vstream_*printf() routines may silently expand a
+/* buffer, so that the result of some %letter specifiers can
+/* be written to contiguous memory.
/*
/* NOTE: the VSTREAM_CTL_BUFSIZE argument type is ssize_t, not
/* int. Use an explicit cast to avoid problems on LP64
ssize_t used = bp->ptr - bp->data;
const char *myname = "vstream_buf_alloc";
- if (len < bp->len)
- msg_panic("%s: attempt to shrink buffer", myname);
+ /*
+ * Don't shrink a non-empty read buffer, or a non-flushed write buffer.
+ */
+ if (len <= 0)
+ msg_panic("%s: bad buffer length: %ld", myname, (long) len);
+ if (len < bp->len
+ && (((bp->flags & VSTREAM_FLAG_READ) && bp->cnt != 0)
+ || ((bp->flags & VSTREAM_FLAG_WRITE) && bp->cnt != bp->len)))
+ msg_panic("%s: attempt to shrink non-empty buffer", myname);
if (bp->flags & VSTREAM_FLAG_FIXED)
- msg_panic("%s: unable to extend fixed-size buffer", myname);
+ msg_panic("%s: attempt to resize fixed-length buffer", myname);
/*
* Late buffer allocation allows the user to override the default policy.
* allocation gives the application a chance to override the default
* buffering policy.
*/
- if (bp->len < stream->req_bufsize)
+ if (bp->len != stream->req_bufsize)
vstream_buf_alloc(bp, stream->req_bufsize);
/*
if (VSTREAM_FFLUSH_SOME(stream))
return (VSTREAM_EOF);
}
+ if (bp->len > stream->req_bufsize)
+ vstream_buf_alloc(bp, stream->req_bufsize);
return (0);
}
if (req_bufsize < 0)
msg_panic("VSTREAM_CTL_BUFSIZE with negative size: %ld",
(long) req_bufsize);
- if (stream != VSTREAM_ERR
- && req_bufsize > stream->req_bufsize)
+ if (req_bufsize > 0 && stream != VSTREAM_ERR)
stream->req_bufsize = req_bufsize;
break;
return (0);
}
}
+
+#ifdef TEST
+
+static void copy_line(ssize_t bufsize)
+{
+ int c;
+
+ vstream_control(VSTREAM_IN, VSTREAM_CTL_BUFSIZE, bufsize, VSTREAM_CTL_END);
+ vstream_control(VSTREAM_OUT, VSTREAM_CTL_BUFSIZE, bufsize, VSTREAM_CTL_END);
+ while ((c = VSTREAM_GETC(VSTREAM_IN)) != VSTREAM_EOF) {
+ VSTREAM_PUTC(c, VSTREAM_OUT);
+ if (c == '\n')
+ break;
+ }
+ vstream_fflush(VSTREAM_OUT);
+}
+
+static void printf_number(void)
+{
+ vstream_printf("%d\n", __MAXINT__(int));
+ vstream_fflush(VSTREAM_OUT);
+}
+
+ /*
+ * Exercise some of the features.
+ */
+int main(int argc, char **argv)
+{
+
+ /*
+ * Test buffer expansion and shrinking. Formatted print may silently
+ * expand the write buffer and cause multiple bytes to be written.
+ */
+ copy_line(1); /* one-byte read/write */
+ copy_line(2); /* two-byte read/write */
+ copy_line(1); /* one-byte read/write */
+ printf_number(); /* multi-byte write */
+ exit(0);
+}
+
+#endif
extern int vstream_tweak_sock(VSTREAM *);
extern int vstream_tweak_tcp(VSTREAM *);
+#define vstream_flags(stream) ((const int) (stream)->buf.flags)
+
/* LICENSE
/* .ad
/* .fi