Postfix3.3.1
resolve_clnt.c
[詳解]
1 /*++
2 /* NAME
3 /* resolve_clnt 3
4 /* SUMMARY
5 /* address resolve service client (internal forms)
6 /* SYNOPSIS
7 /* #include <resolve_clnt.h>
8 /*
9 /* typedef struct {
10 /* .in +4
11 /* VSTRING *transport;
12 /* VSTRING *nexthop
13 /* VSTRING *recipient;
14 /* int flags;
15 /* .in -4
16 /* } RESOLVE_REPLY;
17 /*
18 /* void resolve_clnt_init(reply)
19 /* RESOLVE_REPLY *reply;
20 /*
21 /* void resolve_clnt_query_from(sender, address, reply)
22 /* const char *sender;
23 /* const char *address;
24 /* RESOLVE_REPLY *reply;
25 /*
26 /* void resolve_clnt_verify_from(sender, address, reply)
27 /* const char *sender;
28 /* const char *address;
29 /* RESOLVE_REPLY *reply;
30 /*
31 /* void resolve_clnt_free(reply)
32 /* RESOLVE_REPLY *reply;
33 /* DESCRIPTION
34 /* This module implements a mail address resolver client.
35 /*
36 /* resolve_clnt_init() initializes a reply data structure for use
37 /* by resolve_clnt_query(). The structure is destroyed by passing
38 /* it to resolve_clnt_free().
39 /*
40 /* resolve_clnt_query_from() sends an internal-form recipient address
41 /* (user@domain) to the resolver daemon and returns the resulting
42 /* transport name, next_hop host name, and internal-form recipient
43 /* address. In case of communication failure the program keeps trying
44 /* until the mail system goes down. The internal-form sender
45 /* information is used for sender-dependent relayhost lookup.
46 /* Specify RESOLVE_NULL_FROM when the sender is unavailable.
47 /*
48 /* resolve_clnt_verify_from() implements an alternative version that can
49 /* be used for address verification.
50 /*
51 /* In the resolver reply, the flags member is the bit-wise OR of
52 /* zero or more of the following:
53 /* .IP RESOLVE_FLAG_FINAL
54 /* The recipient address resolves to a mail transport that performs
55 /* final delivery. The destination is local or corresponds to a hosted
56 /* domain that is handled by the local machine. This flag is currently
57 /* not used.
58 /* .IP RESOLVE_FLAG_ROUTED
59 /* After address resolution the recipient localpart contains further
60 /* routing information, so the resolved next-hop destination is not
61 /* the final destination.
62 /* .IP RESOLVE_FLAG_ERROR
63 /* The address resolved to something that has invalid syntax.
64 /* .IP RESOLVE_FLAG_FAIL
65 /* The request could not be completed.
66 /* .PP
67 /* In addition, the address domain class is returned by setting
68 /* one of the following flags (this is preliminary code awaiting
69 /* more permanent implementation of address domain class handling):
70 /* .IP RESOLVE_CLASS_LOCAL
71 /* The address domain matches $mydestination, $inet_interfaces
72 /* or $proxy_interfaces.
73 /* .IP RESOLVE_CLASS_ALIAS
74 /* The address domain matches $virtual_alias_domains (virtual
75 /* alias domains, where each address is redirected to a real
76 /* local or remote address).
77 /* .IP RESOLVE_CLASS_VIRTUAL
78 /* The address domain matches $virtual_mailbox_domains (true
79 /* virtual domains where each address can have its own mailbox).
80 /* .IP RESOLVE_CLASS_RELAY
81 /* The address domain matches $relay_domains, i.e. this is an
82 /* authorized mail relay destination.
83 /* .IP RESOLVE_CLASS_DEFAULT
84 /* The address matches none of the above. Access to this domain
85 /* should be limited to authorized senders only.
86 /* .PP
87 /* For convenience, the constant RESOLVE_CLASS_FINAL includes all
88 /* cases where the local machine is the final destination.
89 /* DIAGNOSTICS
90 /* Warnings: communication failure. Fatal error: mail system is down.
91 /* SEE ALSO
92 /* mail_proto(3h) low-level mail component glue.
93 /* LICENSE
94 /* .ad
95 /* .fi
96 /* The Secure Mailer license must be distributed with this software.
97 /* AUTHOR(S)
98 /* Wietse Venema
99 /* IBM T.J. Watson Research
100 /* P.O. Box 704
101 /* Yorktown Heights, NY 10598, USA
102 /*
103 /* Wietse Venema
104 /* Google, Inc.
105 /* 111 8th Avenue
106 /* New York, NY 10011, USA
107 /*--*/
108 
109 /* System library. */
110 
111 #include <sys_defs.h>
112 #include <unistd.h>
113 #include <string.h>
114 #include <errno.h>
115 
116 /* Utility library. */
117 
118 #include <msg.h>
119 #include <vstream.h>
120 #include <vstring.h>
121 #include <vstring_vstream.h>
122 #include <events.h>
123 #include <iostuff.h>
124 
125 /* Global library. */
126 
127 #include "mail_proto.h"
128 #include "mail_params.h"
129 #include "clnt_stream.h"
130 #include "resolve_clnt.h"
131 
132 /* Application-specific. */
133 
134  /*
135  * XXX this is shared with the rewrite client to save a file descriptor.
136  */
138 
139 static time_t last_expire;
140 static VSTRING *last_class;
141 static VSTRING *last_sender;
142 static VSTRING *last_addr;
143 static RESOLVE_REPLY last_reply;
144 
145 /* resolve_clnt_init - initialize reply */
146 
148 {
149  reply->transport = vstring_alloc(100);
150  reply->nexthop = vstring_alloc(100);
151  reply->recipient = vstring_alloc(100);
152  reply->flags = 0;
153 }
154 
155 /* resolve_clnt - resolve address to (transport, next hop, recipient) */
156 
157 void resolve_clnt(const char *class, const char *sender,
158  const char *addr, RESOLVE_REPLY *reply)
159 {
160  const char *myname = "resolve_clnt";
161  VSTREAM *stream;
162  int server_flags;
163  int count = 0;
164 
165  /*
166  * One-entry cache.
167  */
168  if (last_addr == 0) {
169  last_class = vstring_alloc(10);
170  last_sender = vstring_alloc(10);
171  last_addr = vstring_alloc(100);
172  resolve_clnt_init(&last_reply);
173  }
174 
175  /*
176  * Sanity check. The result must not clobber the input because we may
177  * have to retransmit the request.
178  */
179 #define STR vstring_str
180 
181  if (addr == STR(reply->recipient))
182  msg_panic("%s: result clobbers input", myname);
183 
184  /*
185  * Peek at the cache.
186  */
187 #define IFSET(flag, text) ((reply->flags & (flag)) ? (text) : "")
188 
189  if (time((time_t *) 0) < last_expire
190  && *addr && strcmp(addr, STR(last_addr)) == 0
191  && strcmp(class, STR(last_class)) == 0
192  && strcmp(sender, STR(last_sender)) == 0) {
193  vstring_strcpy(reply->transport, STR(last_reply.transport));
194  vstring_strcpy(reply->nexthop, STR(last_reply.nexthop));
195  vstring_strcpy(reply->recipient, STR(last_reply.recipient));
196  reply->flags = last_reply.flags;
197  if (msg_verbose)
198  msg_info("%s: cached: `%s' -> `%s' -> transp=`%s' host=`%s' rcpt=`%s' flags=%s%s%s%s class=%s%s%s%s%s",
199  myname, sender, addr, STR(reply->transport),
200  STR(reply->nexthop), STR(reply->recipient),
201  IFSET(RESOLVE_FLAG_FINAL, "final"),
202  IFSET(RESOLVE_FLAG_ROUTED, "routed"),
203  IFSET(RESOLVE_FLAG_ERROR, "error"),
204  IFSET(RESOLVE_FLAG_FAIL, "fail"),
205  IFSET(RESOLVE_CLASS_LOCAL, "local"),
206  IFSET(RESOLVE_CLASS_ALIAS, "alias"),
207  IFSET(RESOLVE_CLASS_VIRTUAL, "virtual"),
208  IFSET(RESOLVE_CLASS_RELAY, "relay"),
209  IFSET(RESOLVE_CLASS_DEFAULT, "default"));
210  return;
211  }
212 
213  /*
214  * Keep trying until we get a complete response. The resolve service is
215  * CPU bound; making the client asynchronous would just complicate the
216  * code.
217  */
218  if (rewrite_clnt_stream == 0)
219  rewrite_clnt_stream = clnt_stream_create(MAIL_CLASS_PRIVATE,
223 
224  for (;;) {
225  stream = clnt_stream_access(rewrite_clnt_stream);
226  errno = 0;
227  count += 1;
228  if (attr_print(stream, ATTR_FLAG_NONE,
232  ATTR_TYPE_END) != 0
233  || vstream_fflush(stream)
234  || attr_scan(stream, ATTR_FLAG_STRICT,
235  RECV_ATTR_INT(MAIL_ATTR_FLAGS, &server_flags),
240  ATTR_TYPE_END) != 5) {
241  if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
242  msg_warn("problem talking to service %s: %m",
244  } else {
245  if (msg_verbose)
246  msg_info("%s: `%s' -> `%s' -> transp=`%s' host=`%s' rcpt=`%s' flags=%s%s%s%s class=%s%s%s%s%s",
247  myname, sender, addr, STR(reply->transport),
248  STR(reply->nexthop), STR(reply->recipient),
249  IFSET(RESOLVE_FLAG_FINAL, "final"),
250  IFSET(RESOLVE_FLAG_ROUTED, "routed"),
251  IFSET(RESOLVE_FLAG_ERROR, "error"),
252  IFSET(RESOLVE_FLAG_FAIL, "fail"),
253  IFSET(RESOLVE_CLASS_LOCAL, "local"),
254  IFSET(RESOLVE_CLASS_ALIAS, "alias"),
255  IFSET(RESOLVE_CLASS_VIRTUAL, "virtual"),
256  IFSET(RESOLVE_CLASS_RELAY, "relay"),
257  IFSET(RESOLVE_CLASS_DEFAULT, "default"));
258  /* Server-requested disconnect. */
259  if (server_flags != 0)
260  clnt_stream_recover(rewrite_clnt_stream);
261  if (STR(reply->transport)[0] == 0)
262  msg_warn("%s: null transport result for: <%s>", myname, addr);
263  else if (STR(reply->recipient)[0] == 0 && *addr != 0)
264  msg_warn("%s: null recipient result for: <%s>", myname, addr);
265  else
266  break;
267  }
268  sleep(1); /* XXX make configurable */
269  clnt_stream_recover(rewrite_clnt_stream);
270  }
271 
272  /*
273  * Update the cache.
274  */
275  vstring_strcpy(last_class, class);
276  vstring_strcpy(last_sender, sender);
277  vstring_strcpy(last_addr, addr);
278  vstring_strcpy(last_reply.transport, STR(reply->transport));
279  vstring_strcpy(last_reply.nexthop, STR(reply->nexthop));
280  vstring_strcpy(last_reply.recipient, STR(reply->recipient));
281  last_reply.flags = reply->flags;
282  last_expire = time((time_t *) 0) + 30; /* XXX make configurable */
283 }
284 
285 /* resolve_clnt_free - destroy reply */
286 
288 {
289  reply->transport = vstring_free(reply->transport);
290  reply->nexthop = vstring_free(reply->nexthop);
291  reply->recipient = vstring_free(reply->recipient);
292 }
293 
294 #ifdef TEST
295 
296 #include <stdlib.h>
297 #include <msg_vstream.h>
298 #include <vstring_vstream.h>
299 #include <split_at.h>
300 #include <mail_conf.h>
301 
302 static NORETURN usage(char *myname)
303 {
304  msg_fatal("usage: %s [-v] [address...]", myname);
305 }
306 
307 static void resolve(char *class, char *addr, RESOLVE_REPLY *reply)
308 {
309  struct RESOLVE_FLAG_TABLE {
310  int flag;
311  const char *name;
312  };
313  struct RESOLVE_FLAG_TABLE resolve_flag_table[] = {
314  RESOLVE_FLAG_FINAL, "FLAG_FINAL",
315  RESOLVE_FLAG_ROUTED, "FLAG_ROUTED",
316  RESOLVE_FLAG_ERROR, "FLAG_ERROR",
317  RESOLVE_FLAG_FAIL, "FLAG_FAIL",
318  RESOLVE_CLASS_LOCAL, "CLASS_LOCAL",
319  RESOLVE_CLASS_ALIAS, "CLASS_ALIAS",
320  RESOLVE_CLASS_VIRTUAL, "CLASS_VIRTUAL",
321  RESOLVE_CLASS_RELAY, "CLASS_RELAY",
322  RESOLVE_CLASS_DEFAULT, "CLASS_DEFAULT",
323  0,
324  };
325  struct RESOLVE_FLAG_TABLE *fp;
326 
327  resolve_clnt(class, RESOLVE_NULL_FROM, addr, reply);
328  if (reply->flags & RESOLVE_FLAG_FAIL) {
329  vstream_printf("request failed\n");
330  } else {
331  vstream_printf("%-10s %s\n", "class", class);
332  vstream_printf("%-10s %s\n", "address", addr);
333  vstream_printf("%-10s %s\n", "transport", STR(reply->transport));
334  vstream_printf("%-10s %s\n", "nexthop", *STR(reply->nexthop) ?
335  STR(reply->nexthop) : "[none]");
336  vstream_printf("%-10s %s\n", "recipient", STR(reply->recipient));
337  vstream_printf("%-10s ", "flags");
338  for (fp = resolve_flag_table; fp->name; fp++) {
339  if (reply->flags & fp->flag) {
340  vstream_printf("%s ", fp->name);
341  reply->flags &= ~fp->flag;
342  }
343  }
344  if (reply->flags != 0)
345  vstream_printf("Unknown flag 0x%x", reply->flags);
346  vstream_printf("\n\n");
348  }
349 }
350 
351 int main(int argc, char **argv)
352 {
353  RESOLVE_REPLY reply;
354  char *addr;
355  int ch;
356 
357  msg_vstream_init(argv[0], VSTREAM_ERR);
358 
359  mail_conf_read();
360  msg_info("using config files in %s", var_config_dir);
361  if (chdir(var_queue_dir) < 0)
362  msg_fatal("chdir %s: %m", var_queue_dir);
363 
364  while ((ch = GETOPT(argc, argv, "v")) > 0) {
365  switch (ch) {
366  case 'v':
367  msg_verbose++;
368  break;
369  default:
370  usage(argv[0]);
371  }
372  }
373  resolve_clnt_init(&reply);
374 
375  if (argc > optind) {
376  while (argv[optind] && argv[optind + 1]) {
377  resolve(argv[optind], argv[optind + 1], &reply);
378  optind += 2;
379  }
380  } else {
381  VSTRING *buffer = vstring_alloc(1);
382 
383  while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
384  addr = split_at(STR(buffer), ' ');
385  if (*STR(buffer) == 0)
386  msg_fatal("need as input: class [address]");
387  if (addr == 0)
388  addr = "";
389  resolve(STR(buffer), addr, &reply);
390  }
391  vstring_free(buffer);
392  }
393  resolve_clnt_free(&reply);
394  exit(0);
395 }
396 
397 #endif
int msg_verbose
Definition: msg.c:177
#define vstring_fgets_nonl(s, p)
#define RESOLVE_FLAG_FAIL
Definition: resolve_clnt.h:28
#define ATTR_FLAG_NONE
Definition: attr.h:98
#define RESOLVE_NULL_FROM
Definition: resolve_clnt.h:54
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
CLNT_STREAM * rewrite_clnt_stream
Definition: rewrite_clnt.c:73
#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
#define RECV_ATTR_INT(name, val)
Definition: attr.h:71
#define ATTR_TYPE_END
Definition: attr.h:39
void resolve_clnt_free(RESOLVE_REPLY *reply)
Definition: resolve_clnt.c:287
char * var_config_dir
Definition: mail_params.c:241
#define VSTREAM_IN
Definition: vstream.h:66
#define MAIL_ATTR_ADDR
Definition: mail_proto.h:146
#define RESOLVE_FLAG_ROUTED
Definition: resolve_clnt.h:26
#define RESOLVE_CLASS_VIRTUAL
Definition: resolve_clnt.h:32
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
void mail_conf_read(void)
Definition: mail_conf.c:178
#define MAIL_ATTR_TRANSPORT
Definition: mail_proto.h:147
#define RESOLVE_CLASS_LOCAL
Definition: resolve_clnt.h:30
#define attr_print
Definition: attr.h:109
#define RESOLVE_FLAG_ERROR
Definition: resolve_clnt.h:27
void resolve_clnt_init(RESOLVE_REPLY *reply)
Definition: resolve_clnt.c:147
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
#define STR
char * var_rewrite_service
Definition: mail_params.c:306
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
VSTRING * recipient
Definition: resolve_clnt.h:46
#define MAIL_ATTR_NEXTHOP
Definition: mail_proto.h:148
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
#define GETOPT(argc, argv, str)
Definition: sys_defs.h:1313
#define RESOLVE_FLAG_FINAL
Definition: resolve_clnt.h:25
#define IFSET(flag, text)
#define RESOLVE_CLASS_RELAY
Definition: resolve_clnt.h:33
#define RESOLVE_CLASS_ALIAS
Definition: resolve_clnt.h:31
#define MAIL_ATTR_RECIP
Definition: mail_proto.h:134
void resolve_clnt(const char *class, const char *sender, const char *addr, RESOLVE_REPLY *reply)
Definition: resolve_clnt.c:157
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
VSTRING * nexthop
Definition: resolve_clnt.h:45
char * var_queue_dir
Definition: mail_params.c:246
#define MAIL_ATTR_SENDER
Definition: mail_proto.h:131
VSTRING * transport
Definition: resolve_clnt.h:44
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
#define RESOLVE_CLASS_DEFAULT
Definition: resolve_clnt.h:34
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