Postfix3.3.1
rewrite_clnt.c
[詳解]
1 /*++
2 /* NAME
3 /* rewrite_clnt 3
4 /* SUMMARY
5 /* address rewrite service client
6 /* SYNOPSIS
7 /* #include <vstring.h>
8 /* #include <rewrite_clnt.h>
9 /*
10 /* VSTRING *rewrite_clnt(ruleset, address, result)
11 /* const char *ruleset;
12 /* const char *address;
13 /*
14 /* VSTRING *rewrite_clnt_internal(ruleset, address, result)
15 /* const char *ruleset;
16 /* const char *address;
17 /* VSTRING *result;
18 /* DESCRIPTION
19 /* This module implements a mail address rewriting client.
20 /*
21 /* rewrite_clnt() sends a rule set name and external-form address to the
22 /* rewriting service and returns the resulting external-form address.
23 /* In case of communication failure the program keeps trying until the
24 /* mail system shuts down.
25 /*
26 /* rewrite_clnt_internal() performs the same functionality but takes
27 /* input in internal (unquoted) form, and produces output in internal
28 /* (unquoted) form.
29 /* DIAGNOSTICS
30 /* Warnings: communication failure. Fatal error: mail system is down.
31 /* SEE ALSO
32 /* mail_proto(3h) low-level mail component glue.
33 /* LICENSE
34 /* .ad
35 /* .fi
36 /* The Secure Mailer license must be distributed with this software.
37 /* AUTHOR(S)
38 /* Wietse Venema
39 /* IBM T.J. Watson Research
40 /* P.O. Box 704
41 /* Yorktown Heights, NY 10598, USA
42 /*--*/
43 
44 /* System library. */
45 
46 #include <sys_defs.h>
47 #include <unistd.h>
48 #include <errno.h>
49 #include <string.h>
50 
51 /* Utility library. */
52 
53 #include <msg.h>
54 #include <vstring.h>
55 #include <vstream.h>
56 #include <vstring_vstream.h>
57 #include <events.h>
58 #include <iostuff.h>
59 #include <quote_822_local.h>
60 
61 /* Global library. */
62 
63 #include "mail_proto.h"
64 #include "mail_params.h"
65 #include "clnt_stream.h"
66 #include "rewrite_clnt.h"
67 
68 /* Application-specific. */
69 
70  /*
71  * XXX this is shared with the resolver client to save a file descriptor.
72  */
74 
75 static time_t last_expire;
76 static VSTRING *last_rule;
77 static VSTRING *last_addr;
78 static VSTRING *last_result;
79 
80 /* rewrite_clnt - rewrite address to (transport, next hop, recipient) */
81 
82 VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result)
83 {
84  VSTREAM *stream;
85  int server_flags;
86  int count = 0;
87 
88  /*
89  * One-entry cache.
90  */
91  if (last_addr == 0) {
92  last_rule = vstring_alloc(10);
93  last_addr = vstring_alloc(100);
94  last_result = vstring_alloc(100);
95  }
96 
97  /*
98  * Sanity check. An address must be in externalized form. The result must
99  * not clobber the input, because we may have to retransmit the query.
100  */
101 #define STR vstring_str
102 
103  if (*addr == 0)
104  addr = "";
105  if (addr == STR(result))
106  msg_panic("rewrite_clnt: result clobbers input");
107 
108  /*
109  * Peek at the cache.
110  */
111  if (time((time_t *) 0) < last_expire
112  && strcmp(addr, STR(last_addr)) == 0
113  && strcmp(rule, STR(last_rule)) == 0) {
114  vstring_strcpy(result, STR(last_result));
115  if (msg_verbose)
116  msg_info("rewrite_clnt: cached: %s: %s -> %s",
117  rule, addr, vstring_str(result));
118  return (result);
119  }
120 
121  /*
122  * Keep trying until we get a complete response. The rewrite service is
123  * CPU bound and making the client asynchronous would just complicate the
124  * code.
125  */
126  if (rewrite_clnt_stream == 0)
127  rewrite_clnt_stream = clnt_stream_create(MAIL_CLASS_PRIVATE,
131 
132  for (;;) {
133  stream = clnt_stream_access(rewrite_clnt_stream);
134  errno = 0;
135  count += 1;
136  if (attr_print(stream, ATTR_FLAG_NONE,
140  ATTR_TYPE_END) != 0
141  || vstream_fflush(stream)
142  || attr_scan(stream, ATTR_FLAG_STRICT,
143  RECV_ATTR_INT(MAIL_ATTR_FLAGS, &server_flags),
144  RECV_ATTR_STR(MAIL_ATTR_ADDR, result),
145  ATTR_TYPE_END) != 2) {
146  if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
147  msg_warn("problem talking to service %s: %m",
149  } else {
150  if (msg_verbose)
151  msg_info("rewrite_clnt: %s: %s -> %s",
152  rule, addr, vstring_str(result));
153  /* Server-requested disconnect. */
154  if (server_flags != 0)
155  clnt_stream_recover(rewrite_clnt_stream);
156  break;
157  }
158  sleep(1); /* XXX make configurable */
159  clnt_stream_recover(rewrite_clnt_stream);
160  }
161 
162  /*
163  * Update the cache.
164  */
165  vstring_strcpy(last_rule, rule);
166  vstring_strcpy(last_addr, addr);
167  vstring_strcpy(last_result, STR(result));
168  last_expire = time((time_t *) 0) + 30; /* XXX make configurable */
169 
170  return (result);
171 }
172 
173 /* rewrite_clnt_internal - rewrite from/to internal form */
174 
175 VSTRING *rewrite_clnt_internal(const char *ruleset, const char *addr, VSTRING *result)
176 {
177  VSTRING *src = vstring_alloc(100);
178  VSTRING *dst = vstring_alloc(100);
179 
180  /*
181  * Convert the address from internal address form to external RFC822
182  * form, then rewrite it. After rewriting, convert to internal form.
183  */
184  quote_822_local(src, addr);
185  rewrite_clnt(ruleset, STR(src), dst);
186  unquote_822_local(result, STR(dst));
187  vstring_free(src);
188  vstring_free(dst);
189  return (result);
190 }
191 
192 #ifdef TEST
193 
194 #include <stdlib.h>
195 #include <string.h>
196 #include <msg_vstream.h>
197 #include <split_at.h>
198 #include <vstring_vstream.h>
199 #include <mail_conf.h>
200 #include <mail_params.h>
201 
202 static NORETURN usage(char *myname)
203 {
204  msg_fatal("usage: %s [-v] [rule address...]", myname);
205 }
206 
207 static void rewrite(char *rule, char *addr, VSTRING *reply)
208 {
209  rewrite_clnt(rule, addr, reply);
210  vstream_printf("%-10s %s\n", "rule", rule);
211  vstream_printf("%-10s %s\n", "address", addr);
212  vstream_printf("%-10s %s\n\n", "result", STR(reply));
214 }
215 
216 int main(int argc, char **argv)
217 {
218  VSTRING *reply;
219  int ch;
220  char *rule;
221  char *addr;
222 
223  msg_vstream_init(argv[0], VSTREAM_ERR);
224 
225  mail_conf_read();
226  msg_info("using config files in %s", var_config_dir);
227  if (chdir(var_queue_dir) < 0)
228  msg_fatal("chdir %s: %m", var_queue_dir);
229 
230  while ((ch = GETOPT(argc, argv, "v")) > 0) {
231  switch (ch) {
232  case 'v':
233  msg_verbose++;
234  break;
235  default:
236  usage(argv[0]);
237  }
238  }
239  reply = vstring_alloc(1);
240 
241  if (argc > optind) {
242  for (;;) {
243  if ((rule = argv[optind++]) == 0)
244  break;
245  if ((addr = argv[optind++]) == 0)
246  usage(argv[0]);
247  rewrite(rule, addr, reply);
248  }
249  } else {
250  VSTRING *buffer = vstring_alloc(1);
251 
252  while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
253  if ((addr = split_at(STR(buffer), ' ')) == 0
254  || *(rule = STR(buffer)) == 0)
255  usage(argv[0]);
256  rewrite(rule, addr, reply);
257  }
258  vstring_free(buffer);
259  }
260  vstring_free(reply);
261  exit(0);
262 }
263 
264 #endif
int msg_verbose
Definition: msg.c:177
CLNT_STREAM * rewrite_clnt_stream
Definition: rewrite_clnt.c:73
#define vstring_fgets_nonl(s, p)
#define ATTR_FLAG_NONE
Definition: attr.h:98
#define STR
VSTREAM * clnt_stream_access(CLNT_STREAM *clnt_stream)
Definition: clnt_stream.c:206
#define NORETURN
Definition: sys_defs.h:1583
int var_ipc_idle_limit
Definition: mail_params.c:268
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define vstring_str(vp)
Definition: vstring.h:71
#define VSTREAM_OUT
Definition: vstream.h:67
#define MAIL_ATTR_REQ
Definition: mail_proto.h:124
int main(int argc, char **argv)
Definition: anvil.c:1010
VSTRING * rewrite_clnt_internal(const char *ruleset, const char *addr, VSTRING *result)
Definition: rewrite_clnt.c:175
VSTRING * unquote_822_local(VSTRING *dst, const char *mbox)
#define RECV_ATTR_INT(name, val)
Definition: attr.h:71
#define ATTR_TYPE_END
Definition: attr.h:39
char * var_config_dir
Definition: mail_params.c:241
#define MAIL_ATTR_RULE
Definition: mail_proto.h:145
#define VSTREAM_IN
Definition: vstream.h:66
#define MAIL_ATTR_ADDR
Definition: mail_proto.h:146
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
void mail_conf_read(void)
Definition: mail_conf.c:178
#define attr_print
Definition: attr.h:109
CLNT_STREAM * clnt_stream_create(const char *class, const char *service, int timeout, int ttl)
Definition: clnt_stream.c:228
int var_ipc_ttl_limit
Definition: mail_params.c:269
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
char * var_rewrite_service
Definition: mail_params.c:306
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
#define GETOPT(argc, argv, str)
Definition: sys_defs.h:1313
#define quote_822_local(dst, src)
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
char * var_queue_dir
Definition: mail_params.c:246
#define REWRITE_ADDR
Definition: rewrite_clnt.h:27
char * split_at(char *string, int delimiter)
Definition: split_at.c:53
void msg_vstream_init(const char *name, VSTREAM *vp)
Definition: msg_vstream.c:77
void clnt_stream_recover(CLNT_STREAM *clnt_stream)
Definition: clnt_stream.c:194
VSTRING * rewrite_clnt(const char *rule, const char *addr, VSTRING *result)
Definition: rewrite_clnt.c:82
int server_flags
#define attr_scan
Definition: attr.h:111
#define SEND_ATTR_STR(name, val)
Definition: attr.h:64
#define MAIL_ATTR_FLAGS
Definition: mail_proto.h:128
#define MAIL_CLASS_PRIVATE
Definition: mail_proto.h:96
#define VSTREAM_ERR
Definition: vstream.h:68
#define RECV_ATTR_STR(name, val)
Definition: attr.h:72
#define ATTR_FLAG_STRICT
Definition: attr.h:103
void msg_info(const char *fmt,...)
Definition: msg.c:199