Postfix3.3.1
resolve_local.c
[詳解]
1 /*++
2 /* NAME
3 /* resolve_local 3
4 /* SUMMARY
5 /* determine if domain resolves to local mail system
6 /* SYNOPSIS
7 /* #include <resolve_local.h>
8 /*
9 /* void resolve_local_init()
10 /*
11 /* int resolve_local(domain)
12 /* const char *domain;
13 /* DESCRIPTION
14 /* resolve_local() determines if the named domain resolves to the
15 /* local mail system, either by case-insensitive exact match
16 /* against the domains, files or tables listed in $mydestination,
17 /* or by a match of an [address-literal] against of the network
18 /* addresses listed in $inet_interfaces or in $proxy_interfaces.
19 /* The result is > 0 if the domain matches the list of local
20 /* domains and IP addresses, 0 when it does not match, and < 0
21 /* in case of error.
22 /*
23 /* resolve_local_init() performs initialization. If this routine is
24 /* not called explicitly ahead of time, it will be called on the fly.
25 /* BUGS
26 /* Calling resolve_local_init() on the fly is an incomplete solution.
27 /* It is bound to fail with applications that enter a chroot jail.
28 /* SEE ALSO
29 /* own_inet_addr(3), find out my own network interfaces
30 /* match_list(3), generic pattern matching engine
31 /* match_ops(3), generic pattern matching operators
32 /* LICENSE
33 /* .ad
34 /* .fi
35 /* The Secure Mailer license must be distributed with this software.
36 /* AUTHOR(S)
37 /* Wietse Venema
38 /* IBM T.J. Watson Research
39 /* P.O. Box 704
40 /* Yorktown Heights, NY 10598, USA
41 /*--*/
42 
43 /* System library. */
44 
45 #include <sys_defs.h>
46 
47 /* Utility library. */
48 
49 #include <msg.h>
50 #include <mymalloc.h>
51 #include <string_list.h>
52 #include <myaddrinfo.h>
53 #include <valid_mailhost_addr.h>
54 
55 /* Global library. */
56 
57 #include <mail_params.h>
58 #include <own_inet_addr.h>
59 #include <resolve_local.h>
60 
61 /* Application-specific */
62 
63 static STRING_LIST *resolve_local_list;
64 
65 /* resolve_local_init - initialize lookup table */
66 
68 {
69  /* Allow on-the-fly update to make testing easier. */
70  if (resolve_local_list)
71  string_list_free(resolve_local_list);
72  resolve_local_list = string_list_init(VAR_MYDEST, MATCH_FLAG_RETURN,
73  var_mydest);
74 }
75 
76 /* resolve_local - match domain against list of local destinations */
77 
78 int resolve_local(const char *addr)
79 {
80  char *saved_addr = mystrdup(addr);
81  char *dest;
82  const char *bare_dest;
83  struct addrinfo *res0 = 0;
84  ssize_t len;
85 
86  /*
87  * The optimizer will eliminate tests that always fail.
88  */
89 #define RETURN(x) \
90  do { \
91  myfree(saved_addr); \
92  if (res0) \
93  freeaddrinfo(res0); \
94  return(x); \
95  } while (0)
96 
97  if (resolve_local_list == 0)
99 
100  /*
101  * Strip one trailing dot but not dot-dot.
102  *
103  * XXX This should not be distributed all over the code. Problem is,
104  * addresses can enter the system via multiple paths: networks, local
105  * forward/alias/include files, even as the result of address rewriting.
106  */
107  len = strlen(saved_addr);
108  if (len == 0)
109  RETURN(0);
110  if (saved_addr[len - 1] == '.')
111  saved_addr[--len] = 0;
112  if (len == 0 || saved_addr[len - 1] == '.')
113  RETURN(0);
114 
115  /*
116  * Compare the destination against the list of destinations that we
117  * consider local.
118  */
119  if (string_list_match(resolve_local_list, saved_addr))
120  RETURN(1);
121  if (resolve_local_list->error != 0)
122  RETURN(resolve_local_list->error);
123 
124  /*
125  * Compare the destination against the list of interface addresses that
126  * we are supposed to listen on.
127  *
128  * The destination may be an IPv6 address literal that was buried somewhere
129  * inside a deeply recursively nested address. This information comes
130  * from an untrusted source, and Wietse is not confident that everyone's
131  * getaddrinfo() etc. implementation is sufficiently robust. The syntax
132  * is complex enough with null field compression and with IPv4-in-IPv6
133  * addresses that errors are likely.
134  *
135  * The solution below is ad-hoc. We neutralize the string as soon as we
136  * realize that its contents could be harmful. We neutralize the string
137  * here, instead of neutralizing it in every resolve_local() caller.
138  * That's because resolve_local knows how the address is going to be
139  * parsed and converted into binary form.
140  *
141  * There are several more structural solutions to this.
142  *
143  * - One solution is to disallow address literals. This is not as bad as it
144  * seems: I have never seen actual legitimate use of address literals.
145  *
146  * - Another solution is to label each string with a trustworthiness label
147  * and to expect that all Postfix infrastructure will exercise additional
148  * caution when given a string with untrusted content. This is not likely
149  * to happen.
150  *
151  * FIX 200501 IPv6 patch did not require "IPv6:" prefix in numerical
152  * addresses.
153  */
154  dest = saved_addr;
155  if (*dest == '[' && dest[len - 1] == ']') {
156  dest++;
157  dest[len -= 2] = 0;
158  if ((bare_dest = valid_mailhost_addr(dest, DO_GRIPE)) != 0
159  && hostaddr_to_sockaddr(bare_dest, (char *) 0, 0, &res0) == 0) {
160  if (own_inet_addr(res0->ai_addr) || proxy_inet_addr(res0->ai_addr))
161  RETURN(1);
162  }
163  }
164 
165  /*
166  * Must be remote, or a syntax error.
167  */
168  RETURN(0);
169 }
170 
171 #ifdef TEST
172 
173 #include <vstream.h>
174 #include <mail_conf.h>
175 
176 int main(int argc, char **argv)
177 {
178  int rc;
179 
180  if (argc != 3)
181  msg_fatal("usage: %s mydestination domain", argv[0]);
182  mail_conf_read();
184  var_mydest = mystrdup(argv[1]);
185  vstream_printf("mydestination=%s destination=%s %s\n", argv[1], argv[2],
186  (rc = resolve_local(argv[2])) > 0 ? "YES" :
187  rc == 0 ? "NO" : "ERROR");
189  return (0);
190 }
191 
192 #endif
const char * valid_mailhost_addr(const char *addr, int gripe)
void myfree(void *ptr)
Definition: mymalloc.c:207
#define MATCH_FLAG_RETURN
Definition: match_list.h:40
char * mystrdup(const char *str)
Definition: mymalloc.c:225
#define VSTREAM_OUT
Definition: vstream.h:67
#define STRING_LIST
Definition: string_list.h:22
int main(int argc, char **argv)
Definition: anvil.c:1010
int resolve_local(const char *addr)
Definition: resolve_local.c:78
int own_inet_addr(struct sockaddr *addr)
int hostaddr_to_sockaddr(const char *hostaddr, const char *service, int socktype, struct addrinfo **res)
Definition: myaddrinfo.c:464
void mail_conf_read(void)
Definition: mail_conf.c:178
#define string_list_init(o, f, p)
Definition: string_list.h:24
#define string_list_free
Definition: string_list.h:27
#define string_list_match
Definition: string_list.h:26
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
void resolve_local_init(void)
Definition: resolve_local.c:67
int proxy_inet_addr(struct sockaddr *addr)
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
#define DO_GRIPE
Definition: haproxy_srvr.h:30
#define RETURN(x)
#define VAR_MYDEST
Definition: mail_params.h:133
char * var_mydest
Definition: mail_params.c:226