Postfix3.3.1
postscreen_send.c
[詳解]
1 /*++
2 /* NAME
3 /* postscreen_send 3
4 /* SUMMARY
5 /* postscreen low-level output
6 /* SYNOPSIS
7 /* #include <postscreen.h>
8 /*
9 /* int psc_send_reply(state, text)
10 /* PSC_STATE *state;
11 /* const char *text;
12 /*
13 /* int PSC_SEND_REPLY(state, text)
14 /* PSC_STATE *state;
15 /* const char *text;
16 /*
17 /* void psc_send_socket(state)
18 /* PSC_STATE *state;
19 /* DESCRIPTION
20 /* psc_send_reply() sends the specified text to the specified
21 /* remote SMTP client. In case of an immediate error, it logs
22 /* a warning (except EPIPE) with the client address and port,
23 /* and returns a non-zero result (all errors including EPIPE).
24 /*
25 /* psc_send_reply() does a best effort to send the reply, but
26 /* it won't block when the output is throttled by a hostile
27 /* peer.
28 /*
29 /* PSC_SEND_REPLY() is a legacy wrapper for psc_send_reply().
30 /* It will eventually be replaced by its expansion.
31 /*
32 /* psc_send_socket() sends the specified socket to the real
33 /* Postfix SMTP server. The socket is delivered in the background.
34 /* This function must be called after all other session-related
35 /* work is finished including postscreen cache updates.
36 /*
37 /* In case of an immediate error, psc_send_socket() sends a 421
38 /* reply to the remote SMTP client and closes the connection.
39 /* If the 220- greeting was sent, sending 421 would be invalid;
40 /* instead, the client is redirected to the dummy SMTP engine
41 /* which sends the 421 reply at the first legitimate opportunity.
42 /* LICENSE
43 /* .ad
44 /* .fi
45 /* The Secure Mailer license must be distributed with this software.
46 /* AUTHOR(S)
47 /* Wietse Venema
48 /* IBM T.J. Watson Research
49 /* P.O. Box 704
50 /* Yorktown Heights, NY 10598, USA
51 /*--*/
52 
53 /* System library. */
54 
55 #include <sys_defs.h>
56 #include <string.h>
57 #include <errno.h>
58 
59 /* Utility library. */
60 
61 #include <msg.h>
62 #include <iostuff.h>
63 #include <connect.h>
64 #include <attr.h>
65 #include <vstream.h>
66 
67 /* Global library. */
68 
69 #include <mail_params.h>
70 #include <smtp_reply_footer.h>
71 #include <mail_proto.h>
72 
73 /* Application-specific. */
74 
75 #include <postscreen.h>
76 
77  /*
78  * This program screens all inbound SMTP connections, so it better not waste
79  * time.
80  */
81 #define PSC_SEND_SOCK_CONNECT_TIMEOUT 1
82 #define PSC_SEND_SOCK_NOTIFY_TIMEOUT 100
83 
84 /* psc_send_reply - send reply to remote SMTP client */
85 
86 int psc_send_reply(PSC_STATE *state, const char *text)
87 {
88  ssize_t start;
89  int ret;
90 
91  if (msg_verbose)
92  msg_info("> [%s]:%s: %.*s", state->smtp_client_addr,
93  state->smtp_client_port, (int) strlen(text) - 2, text);
94 
95  /*
96  * Append the new text to earlier text that could not be sent because the
97  * output was throttled.
98  */
99  start = VSTRING_LEN(state->send_buf);
100  vstring_strcat(state->send_buf, text);
101 
102  /*
103  * For soft_bounce support, we also fix the REJECT logging before the
104  * dummy SMTP engine calls the psc_send_reply() output routine. We do
105  * some double work, but it is for debugging only.
106  */
107  if (var_soft_bounce) {
108  if (text[0] == '5')
109  STR(state->send_buf)[start + 0] = '4';
110  if (text[4] == '5')
111  STR(state->send_buf)[start + 4] = '4';
112  }
113 
114  /*
115  * Append the optional reply footer.
116  */
117  if (*var_psc_rej_footer && (*text == '4' || *text == '5'))
120  (void *) state);
121 
122  /*
123  * Do a best effort sending text, but don't block when the output is
124  * throttled by a hostile peer.
125  */
126  ret = write(vstream_fileno(state->smtp_client_stream),
127  STR(state->send_buf), LEN(state->send_buf));
128  if (ret > 0)
129  vstring_truncate(state->send_buf, ret - LEN(state->send_buf));
130  if (ret < 0 && errno != EAGAIN && errno != EPIPE && errno != ECONNRESET)
131  msg_warn("write [%s]:%s: %m", state->smtp_client_addr,
132  state->smtp_client_port);
133  return (ret < 0 && errno != EAGAIN);
134 }
135 
136 /* psc_send_socket_close_event - file descriptor has arrived or timeout */
137 
138 static void psc_send_socket_close_event(int event, void *context)
139 {
140  const char *myname = "psc_send_socket_close_event";
141  PSC_STATE *state = (PSC_STATE *) context;
142 
143  if (msg_verbose > 1)
144  msg_info("%s: sq=%d cq=%d event %d on send socket %d from [%s]:%s",
146  event, state->smtp_server_fd, state->smtp_client_addr,
147  state->smtp_client_port);
148 
149  /*
150  * The real SMTP server has closed the local IPC channel, or we have
151  * reached the limit of our patience. In the latter case it is still
152  * possible that the real SMTP server will receive the socket so we
153  * should not interfere.
154  */
155  PSC_CLEAR_EVENT_REQUEST(state->smtp_server_fd, psc_send_socket_close_event,
156  context);
157  if (event == EVENT_TIME)
158  msg_warn("timeout sending connection to service %s",
160  psc_free_session_state(state);
161 }
162 
163 /* psc_send_socket - send socket to real SMTP server process */
164 
166 {
167  const char *myname = "psc_send_socket";
168  int server_fd;
169  int pass_err;
170  VSTREAM *fp;
171 
172  if (msg_verbose > 1)
173  msg_info("%s: sq=%d cq=%d send socket %d from [%s]:%s",
176  state->smtp_client_addr, state->smtp_client_port);
177 
178  /*
179  * Connect to the real SMTP service over a local IPC channel, send the
180  * file descriptor, and close the file descriptor to save resources.
181  * Experience has shown that some systems will discard information when
182  * we close a channel immediately after writing. Thus, we waste resources
183  * waiting for the remote side to close the local IPC channel first. The
184  * good side of waiting is that we learn when the real SMTP server is
185  * falling behind.
186  *
187  * This is where we would forward the connection to an SMTP server that
188  * provides an appropriate level of service for this client class. For
189  * example, a server that is more forgiving, or one that is more
190  * suspicious. Alternatively, we could send attributes along with the
191  * socket with client reputation information, making everything even more
192  * Postfix-specific.
193  */
194  if ((server_fd =
197  msg_warn("cannot connect to service %s: %m", psc_smtpd_service_name);
198  if (state->flags & PSC_STATE_FLAG_PREGR_TODO) {
199  PSC_SMTPD_X21(state, "421 4.3.2 No system resources\r\n");
200  } else {
201  PSC_SEND_REPLY(state, "421 4.3.2 All server ports are busy\r\n");
202  psc_free_session_state(state);
203  }
204  return;
205  }
206  /* XXX Note: no dummy read between LOCAL_SEND_FD() and attr_print(). */
207  fp = vstream_fdopen(server_fd, O_RDWR);
208  pass_err =
209  (LOCAL_SEND_FD(server_fd,
211  || (attr_print(fp, ATTR_FLAG_NONE,
216  ATTR_TYPE_END) || vstream_fflush(fp)));
217  /* XXX Note: no read between attr_print() and vstream_fdclose(). */
218  (void) vstream_fdclose(fp);
219  if (pass_err != 0) {
220  msg_warn("cannot pass connection to service %s: %m",
222  (void) close(server_fd);
223  if (state->flags & PSC_STATE_FLAG_PREGR_TODO) {
224  PSC_SMTPD_X21(state, "421 4.3.2 No system resources\r\n");
225  } else {
226  PSC_SEND_REPLY(state, "421 4.3.2 No system resources\r\n");
227  psc_free_session_state(state);
228  }
229  return;
230  } else {
231 
232  /*
233  * Closing the smtp_client_fd here triggers a FreeBSD 7.1 kernel bug
234  * where smtp-source sometimes sees the connection being closed after
235  * it has already received the real SMTP server's 220 greeting!
236  */
237 #if 0
238  PSC_DEL_CLIENT_STATE(state);
239 #endif
240  PSC_ADD_SERVER_STATE(state, server_fd);
241  PSC_READ_EVENT_REQUEST(state->smtp_server_fd, psc_send_socket_close_event,
242  (void *) state, PSC_SEND_SOCK_NOTIFY_TIMEOUT);
243  return;
244  }
245 }
int msg_verbose
Definition: msg.c:177
#define ATTR_FLAG_NONE
Definition: attr.h:98
#define PSC_DEL_CLIENT_STATE(state)
Definition: postscreen.h:459
#define PSC_ADD_SERVER_STATE(state, fd)
Definition: postscreen.h:455
int var_soft_bounce
Definition: mail_params.c:281
#define PSC_CLEAR_EVENT_REQUEST(fd, time_act, context)
Definition: postscreen.h:341
char * smtp_client_port
Definition: postscreen.h:75
VSTRING * vstring_truncate(VSTRING *vp, ssize_t len)
Definition: vstring.c:415
#define ATTR_TYPE_END
Definition: attr.h:39
#define MAIL_ATTR_ACT_CLIENT_ADDR
Definition: mail_proto.h:216
#define MAIL_ATTR_ACT_SERVER_ADDR
Definition: mail_proto.h:224
#define LEN
Definition: cleanup_addr.c:106
int psc_check_queue_length
Definition: postscreen.c:527
int flags
Definition: postscreen.h:70
#define PSC_SEND_SOCK_NOTIFY_TIMEOUT
#define VSTRING_LEN(vp)
Definition: vstring.h:72
#define LOCAL_SEND_FD
Definition: sys_defs.h:1426
#define LOCAL_CONNECT
Definition: sys_defs.h:1424
#define attr_print
Definition: attr.h:109
#define MAIL_ATTR_ACT_CLIENT_PORT
Definition: mail_proto.h:217
#define PSC_READ_EVENT_REQUEST(fd, action, context, timeout)
Definition: postscreen.h:325
#define PSC_SEND_SOCK_CONNECT_TIMEOUT
char * smtp_client_addr
Definition: postscreen.h:74
#define STR(x)
Definition: anvil.c:518
void msg_warn(const char *fmt,...)
Definition: msg.c:215
char * smtp_server_addr
Definition: postscreen.h:76
void psc_send_socket(PSC_STATE *state)
#define MAIL_ATTR_ACT_SERVER_PORT
Definition: mail_proto.h:225
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
int smtp_server_fd
Definition: postscreen.h:73
const char * psc_expand_lookup(const char *, int, void *)
VSTRING * psc_expand_filter
char * var_psc_rej_footer
Definition: postscreen.c:512
#define EVENT_TIME
Definition: events.h:43
#define NON_BLOCKING
Definition: iostuff.h:49
VSTRING * send_buf
Definition: postscreen.h:79
int vstream_fdclose(VSTREAM *stream)
Definition: vstream.c:1309
#define vstream_fileno(vp)
Definition: vstream.h:115
#define PSC_SMTPD_X21(state, reply)
Definition: postscreen.h:526
void psc_free_session_state(PSC_STATE *)
#define PSC_SEND_REPLY
Definition: postscreen.h:542
int psc_post_queue_length
Definition: postscreen.c:528
char * smtp_server_port
Definition: postscreen.h:77
#define SEND_ATTR_STR(name, val)
Definition: attr.h:64
VSTRING * vstring_strcat(VSTRING *vp, const char *src)
Definition: vstring.c:459
VSTREAM * smtp_client_stream
Definition: postscreen.h:72
#define PSC_STATE_FLAG_PREGR_TODO
Definition: postscreen.h:188
VSTREAM * vstream_fdopen(int fd, int flags)
Definition: vstream.c:1204
int psc_send_reply(PSC_STATE *state, const char *text)
char * psc_smtpd_service_name
Definition: postscreen.c:531
void msg_info(const char *fmt,...)
Definition: msg.c:199