Postfix3.3.1
smtp_reuse.c
[詳解]
1 /*++
2 /* NAME
3 /* smtp_reuse 3
4 /* SUMMARY
5 /* SMTP session cache glue
6 /* SYNOPSIS
7 /* #include <smtp.h>
8 /* #include <smtp_reuse.h>
9 /*
10 /* void smtp_save_session(state, name_key_flags, endp_key_flags)
11 /* SMTP_STATE *state;
12 /* int name_key_flags;
13 /* int endp_key_flags;
14 /*
15 /* SMTP_SESSION *smtp_reuse_nexthop(state, name_key_flags)
16 /* SMTP_STATE *state;
17 /* int name_key_flags;
18 /*
19 /* SMTP_SESSION *smtp_reuse_addr(state, endp_key_flags)
20 /* SMTP_STATE *state;
21 /* int endp_key_flags;
22 /* DESCRIPTION
23 /* This module implements the SMTP client specific interface to
24 /* the generic session cache infrastructure.
25 /*
26 /* A cached connection is closed when the TLS policy requires
27 /* that TLS is enabled.
28 /*
29 /* smtp_save_session() stores the current session under the
30 /* next-hop logical destination (if available) and under the
31 /* remote server address. The SMTP_SESSION object is destroyed.
32 /*
33 /* smtp_reuse_nexthop() looks up a cached session by its logical
34 /* destination, and verifies that the session is still alive.
35 /* The restored session information includes the "best MX" bit
36 /* and overrides the iterator dest, host and addr fields.
37 /* The result is null in case of failure.
38 /*
39 /* smtp_reuse_addr() looks up a cached session by its server
40 /* address, and verifies that the session is still alive.
41 /* The restored session information does not include the "best
42 /* MX" bit, and does not override the iterator dest, host and
43 /* addr fields.
44 /* The result is null in case of failure.
45 /*
46 /* Arguments:
47 /* .IP state
48 /* SMTP client state, including the current session, the original
49 /* next-hop domain, etc.
50 /* .IP name_key_flags
51 /* Explicit declaration of context that should be used to look
52 /* up a cached connection by its logical destination.
53 /* See smtp_key(3) for details.
54 /* .IP endp_key_flags
55 /* Explicit declaration of context that should be used to look
56 /* up a cached connection by its server address.
57 /* See smtp_key(3) for details.
58 /* LICENSE
59 /* .ad
60 /* .fi
61 /* The Secure Mailer license must be distributed with this software.
62 /* AUTHOR(S)
63 /* Wietse Venema
64 /* IBM T.J. Watson Research
65 /* P.O. Box 704
66 /* Yorktown Heights, NY 10598, USA
67 /*--*/
68 
69 /* System library. */
70 
71 #include <sys_defs.h>
72 #include <sys/socket.h>
73 #include <netinet/in.h>
74 #include <arpa/inet.h>
75 #include <unistd.h>
76 #include <string.h>
77 
78 /* Utility library. */
79 
80 #include <msg.h>
81 #include <mymalloc.h>
82 #include <vstream.h>
83 #include <vstring.h>
84 #include <htable.h>
85 #include <stringops.h>
86 
87 /* Global library. */
88 
89 #include <scache.h>
90 #include <mail_params.h>
91 
92 /* Application-specific. */
93 
94 #include <smtp.h>
95 #include <smtp_reuse.h>
96 
97  /*
98  * Key field delimiter, and place holder field value for
99  * unavailable/inapplicable information.
100  */
101 #define SMTP_REUSE_KEY_DELIM_NA "\n*"
102 
103 /* smtp_save_session - save session under next-hop name and server address */
104 
105 void smtp_save_session(SMTP_STATE *state, int name_key_flags,
106  int endp_key_flags)
107 {
108  SMTP_SESSION *session = state->session;
109  int fd;
110 
111  /*
112  * Encode the next-hop logical destination, if available. Reuse storage
113  * that is also used for cache lookup queries.
114  */
115  if (HAVE_NEXTHOP_STATE(state))
117  state->iterator, name_key_flags);
118 
119  /*
120  * Encode the physical endpoint name. Reuse storage that is also used for
121  * cache lookup queries.
122  */
124  state->iterator, endp_key_flags);
125 
126  /*
127  * Passivate the SMTP_SESSION object, destroying the object in the
128  * process. Reuse storage that is also used for cache lookup results.
129  */
130  fd = smtp_session_passivate(session, state->dest_prop, state->endp_prop);
131  state->session = 0;
132 
133  /*
134  * Save the session under the next-hop name, if available.
135  *
136  * XXX The logical to physical binding can be kept for as long as the DNS
137  * allows us to (but that could result in the caching of lots of unused
138  * bindings). The session should be idle for no more than 30 seconds or
139  * so.
140  */
141  if (HAVE_NEXTHOP_STATE(state))
143  STR(state->dest_prop), STR(state->endp_label));
144 
145  /*
146  * Save every good session under its physical endpoint address.
147  */
149  STR(state->endp_prop), fd);
150 }
151 
152 /* smtp_reuse_common - common session reuse code */
153 
154 static SMTP_SESSION *smtp_reuse_common(SMTP_STATE *state, int fd,
155  const char *label)
156 {
157  const char *myname = "smtp_reuse_common";
158  SMTP_ITERATOR *iter = state->iterator;
159  SMTP_SESSION *session;
160 
161  /*
162  * Can't happen. Both smtp_reuse_nexthop() and smtp_reuse_addr() decline
163  * the request when the TLS policy is not TLS_LEV_NONE.
164  */
165 #ifdef USE_TLS
166  if (state->tls->level > TLS_LEV_NONE)
167  msg_panic("%s: unexpected plain-text cached session to %s",
168  myname, label);
169 #endif
170 
171  /*
172  * Re-activate the SMTP_SESSION object.
173  */
174  session = smtp_session_activate(fd, state->iterator, state->dest_prop,
175  state->endp_prop);
176  if (session == 0) {
177  msg_warn("%s: bad cached session attribute for %s", myname, label);
178  (void) close(fd);
179  return (0);
180  }
181  state->session = session;
182  session->state = state;
183 
184  /*
185  * Send an RSET probe to verify that the session is still good.
186  */
187  if (smtp_rset(state) < 0
188  || (session->features & SMTP_FEATURE_RSET_REJECTED) != 0) {
189  smtp_session_free(session);
190  return (state->session = 0);
191  }
192 
193  /*
194  * Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE.
195  */
196  vstream_tweak_sock(session->stream);
197 
198  /*
199  * Update the list of used cached addresses.
200  */
201  htable_enter(state->cache_used, STR(iter->addr), (void *) 0);
202 
203  return (session);
204 }
205 
206 /* smtp_reuse_nexthop - reuse session cached under nexthop name */
207 
208 SMTP_SESSION *smtp_reuse_nexthop(SMTP_STATE *state, int name_key_flags)
209 {
210  SMTP_SESSION *session;
211  int fd;
212 
213  /*
214  * Don't look up an existing plaintext connection when a new connection
215  * would (try to) use TLS.
216  */
217 #ifdef USE_TLS
218  if (state->tls->level > TLS_LEV_NONE)
219  return (0);
220 #endif
221 
222  /*
223  * Look up the session by its logical name.
224  */
226  state->iterator, name_key_flags);
227  if ((fd = scache_find_dest(smtp_scache, STR(state->dest_label),
228  state->dest_prop, state->endp_prop)) < 0)
229  return (0);
230 
231  /*
232  * Re-activate the SMTP_SESSION object, and verify that the session is
233  * still good.
234  */
235  session = smtp_reuse_common(state, fd, STR(state->dest_label));
236  return (session);
237 }
238 
239 /* smtp_reuse_addr - reuse session cached under numerical address */
240 
241 SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, int endp_key_flags)
242 {
243  SMTP_SESSION *session;
244  int fd;
245 
246  /*
247  * Don't look up an existing plaintext connection when a new connection
248  * would (try to) use TLS.
249  */
250 #ifdef USE_TLS
251  if (state->tls->level > TLS_LEV_NONE)
252  return (0);
253 #endif
254 
255  /*
256  * Look up the session by its IP address. This means that we have no
257  * destination-to-address binding properties.
258  */
260  state->iterator, endp_key_flags);
261  if ((fd = scache_find_endp(smtp_scache, STR(state->endp_label),
262  state->endp_prop)) < 0)
263  return (0);
264  VSTRING_RESET(state->dest_prop);
266 
267  /*
268  * Re-activate the SMTP_SESSION object, and verify that the session is
269  * still good.
270  */
271  session = smtp_reuse_common(state, fd, STR(state->endp_label));
272 
273  return (session);
274 }
SMTP_SESSION * smtp_session_activate(int, SMTP_ITERATOR *, VSTRING *, VSTRING *)
Definition: smtp_session.c:277
VSTRING * endp_prop
Definition: smtp.h:170
SMTP_ITERATOR iterator[1]
Definition: smtp.h:154
struct SMTP_SESSION * session
Definition: smtp.h:147
HTABLE * cache_used
Definition: smtp.h:166
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define scache_find_dest(scache, dest_label, dest_prop, endp_prop)
Definition: scache.h:122
int smtp_rset(SMTP_STATE *)
Definition: smtp_proto.c:2304
#define TLS_LEV_NONE
Definition: tls.h:43
SCACHE * smtp_scache
Definition: smtp.c:967
#define VSTRING_TERMINATE(vp)
Definition: vstring.h:74
void smtp_save_session(SMTP_STATE *state, int name_key_flags, int endp_key_flags)
Definition: smtp_reuse.c:105
#define VSTRING_RESET(vp)
Definition: vstring.h:77
#define STR(x)
Definition: anvil.c:518
VSTRING * addr
Definition: smtp.h:55
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTREAM * stream
Definition: smtp.h:305
#define scache_save_endp(scache, ttl, endp_label, endp_prop, fd)
Definition: scache.h:116
SMTP_SESSION * smtp_reuse_nexthop(SMTP_STATE *state, int name_key_flags)
Definition: smtp_reuse.c:208
VSTRING * endp_label
Definition: smtp.h:169
int var_smtp_cache_conn
Definition: smtp.c:882
VSTRING * dest_prop
Definition: smtp.h:168
#define scache_find_endp(scache, endp_label, endp_prop)
Definition: scache.h:118
SMTP_STATE * state
Definition: smtp.h:346
int vstream_tweak_sock(VSTREAM *)
Definition: vstream_tweak.c:60
#define scache_save_dest(scache, ttl, dest_label, dest_prop, endp_label)
Definition: scache.h:120
int smtp_session_passivate(SMTP_SESSION *, VSTRING *, VSTRING *)
Definition: smtp_session.c:210
int features
Definition: smtp.h:316
VSTRING * dest_label
Definition: smtp.h:167
void smtp_session_free(SMTP_SESSION *)
Definition: smtp_session.c:174
#define HAVE_NEXTHOP_STATE(state)
Definition: smtp.h:198
#define SMTP_FEATURE_RSET_REJECTED
Definition: smtp.h:216
char * smtp_key_prefix(VSTRING *, const char *, SMTP_ITERATOR *, int)
Definition: smtp_key.c:146
SMTP_SESSION * smtp_reuse_addr(SMTP_STATE *state, int endp_key_flags)
Definition: smtp_reuse.c:241
HTABLE_INFO * htable_enter(HTABLE *table, const char *key, void *value)
Definition: htable.c:212
#define SMTP_REUSE_KEY_DELIM_NA
Definition: smtp_reuse.c:101